소스 검색

外部接口

wwh 1 주 전
부모
커밋
258549b6ac

+ 25 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/research/controller/ResearchOpenApiController.java

@@ -20,6 +20,7 @@ import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchDisposab
20 20
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFamilyRanchVo;
21 21
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFarmerHouseholdVo;
22 22
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLargeLivestockFarmerVo;
23
+import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockOwnershipHouseholdVo;
23 24
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockProductOutputVo;
24 25
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchPastureVo;
25 26
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchVaccinationDataVo;
@@ -344,4 +345,28 @@ public class ResearchOpenApiController
344 345
             return ResearchOpenApiSupport.error(code, ex.getMessage());
345 346
         }
346 347
     }
348
+
349
+    /**
350
+     * 有无畜户数据列表(村级汇总)。
351
+     */
352
+    @GetMapping("/livestock-ownership-households")
353
+    public OpenApiResponse<OpenApiPageResult<ResearchLivestockOwnershipHouseholdVo>> listLivestockOwnershipHouseholds(
354
+            @RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
355
+            @RequestParam(value = "pageSize", defaultValue = "20") int pageSize,
356
+            @RequestParam(value = "statYear", required = false) Integer statYear,
357
+            @RequestParam(value = "statMonth", required = false) Integer statMonth,
358
+            @RequestParam(value = "townName", required = false) String townName,
359
+            @RequestParam(value = "villageName", required = false) String villageName)
360
+    {
361
+        try
362
+        {
363
+            return ResearchOpenApiSupport.success(researchOpenApiService.listLivestockOwnershipHouseholds(
364
+                    pageNum, pageSize, statYear, statMonth, townName, villageName));
365
+        }
366
+        catch (ServiceException ex)
367
+        {
368
+            int code = ex.getCode() != null ? ex.getCode() : 500;
369
+            return ResearchOpenApiSupport.error(code, ex.getMessage());
370
+        }
371
+    }
347 372
 }

+ 163 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/research/domain/vo/ResearchLivestockOwnershipHouseholdVo.java

@@ -0,0 +1,163 @@
1
+package com.ruoyi.web.modules.industryservice.research.domain.vo;
2
+
3
+/**
4
+ * 科研开放接口 — 有无畜户填报记录(村级汇总;不含部门 ID / 备注)。
5
+ */
6
+public class ResearchLivestockOwnershipHouseholdVo
7
+{
8
+    /** 有无畜户记录 ID */
9
+    private Long ownershipId;
10
+
11
+    /** 所属年份 */
12
+    private Integer statYear;
13
+
14
+    /** 所属月份(1~12) */
15
+    private Integer statMonth;
16
+
17
+    /** 所属乡镇名称 */
18
+    private String townName;
19
+
20
+    /** 所属村名称 */
21
+    private String villageName;
22
+
23
+    /** 有畜户户数 */
24
+    private Integer withLivestockHouseholdCount;
25
+
26
+    /** 有畜户人数 */
27
+    private Integer withLivestockPopulationCount;
28
+
29
+    /** 有畜户劳动力 */
30
+    private Integer withLivestockLaborCount;
31
+
32
+    /** 有畜户牲畜数 */
33
+    private Integer withLivestockAnimalCount;
34
+
35
+    /** 无畜户户数 */
36
+    private Integer withoutLivestockHouseholdCount;
37
+
38
+    /** 无畜户人数 */
39
+    private Integer withoutLivestockPopulationCount;
40
+
41
+    /** 无畜户劳动力 */
42
+    private Integer withoutLivestockLaborCount;
43
+
44
+    public Long getOwnershipId()
45
+    {
46
+        return ownershipId;
47
+    }
48
+
49
+    public void setOwnershipId(Long ownershipId)
50
+    {
51
+        this.ownershipId = ownershipId;
52
+    }
53
+
54
+    public Integer getStatYear()
55
+    {
56
+        return statYear;
57
+    }
58
+
59
+    public void setStatYear(Integer statYear)
60
+    {
61
+        this.statYear = statYear;
62
+    }
63
+
64
+    public Integer getStatMonth()
65
+    {
66
+        return statMonth;
67
+    }
68
+
69
+    public void setStatMonth(Integer statMonth)
70
+    {
71
+        this.statMonth = statMonth;
72
+    }
73
+
74
+    public String getTownName()
75
+    {
76
+        return townName;
77
+    }
78
+
79
+    public void setTownName(String townName)
80
+    {
81
+        this.townName = townName;
82
+    }
83
+
84
+    public String getVillageName()
85
+    {
86
+        return villageName;
87
+    }
88
+
89
+    public void setVillageName(String villageName)
90
+    {
91
+        this.villageName = villageName;
92
+    }
93
+
94
+    public Integer getWithLivestockHouseholdCount()
95
+    {
96
+        return withLivestockHouseholdCount;
97
+    }
98
+
99
+    public void setWithLivestockHouseholdCount(Integer withLivestockHouseholdCount)
100
+    {
101
+        this.withLivestockHouseholdCount = withLivestockHouseholdCount;
102
+    }
103
+
104
+    public Integer getWithLivestockPopulationCount()
105
+    {
106
+        return withLivestockPopulationCount;
107
+    }
108
+
109
+    public void setWithLivestockPopulationCount(Integer withLivestockPopulationCount)
110
+    {
111
+        this.withLivestockPopulationCount = withLivestockPopulationCount;
112
+    }
113
+
114
+    public Integer getWithLivestockLaborCount()
115
+    {
116
+        return withLivestockLaborCount;
117
+    }
118
+
119
+    public void setWithLivestockLaborCount(Integer withLivestockLaborCount)
120
+    {
121
+        this.withLivestockLaborCount = withLivestockLaborCount;
122
+    }
123
+
124
+    public Integer getWithLivestockAnimalCount()
125
+    {
126
+        return withLivestockAnimalCount;
127
+    }
128
+
129
+    public void setWithLivestockAnimalCount(Integer withLivestockAnimalCount)
130
+    {
131
+        this.withLivestockAnimalCount = withLivestockAnimalCount;
132
+    }
133
+
134
+    public Integer getWithoutLivestockHouseholdCount()
135
+    {
136
+        return withoutLivestockHouseholdCount;
137
+    }
138
+
139
+    public void setWithoutLivestockHouseholdCount(Integer withoutLivestockHouseholdCount)
140
+    {
141
+        this.withoutLivestockHouseholdCount = withoutLivestockHouseholdCount;
142
+    }
143
+
144
+    public Integer getWithoutLivestockPopulationCount()
145
+    {
146
+        return withoutLivestockPopulationCount;
147
+    }
148
+
149
+    public void setWithoutLivestockPopulationCount(Integer withoutLivestockPopulationCount)
150
+    {
151
+        this.withoutLivestockPopulationCount = withoutLivestockPopulationCount;
152
+    }
153
+
154
+    public Integer getWithoutLivestockLaborCount()
155
+    {
156
+        return withoutLivestockLaborCount;
157
+    }
158
+
159
+    public void setWithoutLivestockLaborCount(Integer withoutLivestockLaborCount)
160
+    {
161
+        this.withoutLivestockLaborCount = withoutLivestockLaborCount;
162
+    }
163
+}

+ 10 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/research/service/IResearchOpenApiService.java

@@ -8,6 +8,7 @@ import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchDisposab
8 8
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFamilyRanchVo;
9 9
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFarmerHouseholdVo;
10 10
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLargeLivestockFarmerVo;
11
+import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockOwnershipHouseholdVo;
11 12
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockProductOutputVo;
12 13
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchPastureVo;
13 14
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchVaccinationDataVo;
@@ -118,4 +119,13 @@ public interface IResearchOpenApiService
118 119
      */
119 120
     OpenApiPageResult<ResearchVaccinationDataVo> listVaccinationData(int pageNum, int pageSize,
120 121
             Integer statYear, Integer statMonth, String townName, String villageName);
122
+
123
+    /**
124
+     * 有无畜户填报列表。
125
+     *
126
+     * @param townName 所属乡镇名称模糊匹配
127
+     * @param villageName 所属村名称模糊匹配
128
+     */
129
+    OpenApiPageResult<ResearchLivestockOwnershipHouseholdVo> listLivestockOwnershipHouseholds(int pageNum, int pageSize,
130
+            Integer statYear, Integer statMonth, String townName, String villageName);
121 131
 }

+ 34 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/research/service/impl/ResearchOpenApiServiceImpl.java

@@ -13,6 +13,7 @@ import com.ruoyi.web.modules.industryservice.domain.BizDisposableIncome;
13 13
 import com.ruoyi.web.modules.industryservice.domain.BizFamilyRanch;
14 14
 import com.ruoyi.web.modules.industryservice.domain.BizFarmerHousehold;
15 15
 import com.ruoyi.web.modules.industryservice.domain.BizLargeLivestockFarmer;
16
+import com.ruoyi.web.modules.industryservice.domain.BizLivestockOwnershipHousehold;
16 17
 import com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput;
17 18
 import com.ruoyi.web.modules.industryservice.domain.BizPasture;
18 19
 import com.ruoyi.web.modules.industryservice.domain.BizVaccinationData;
@@ -25,6 +26,7 @@ import com.ruoyi.web.modules.industryservice.mapper.BizDisposableIncomeMapper;
25 26
 import com.ruoyi.web.modules.industryservice.mapper.BizFamilyRanchMapper;
26 27
 import com.ruoyi.web.modules.industryservice.mapper.BizFarmerHouseholdMapper;
27 28
 import com.ruoyi.web.modules.industryservice.mapper.BizLargeLivestockFarmerMapper;
29
+import com.ruoyi.web.modules.industryservice.mapper.BizLivestockOwnershipHouseholdMapper;
28 30
 import com.ruoyi.web.modules.industryservice.mapper.BizLivestockProductOutputMapper;
29 31
 import com.ruoyi.web.modules.industryservice.mapper.BizVaccinationDataMapper;
30 32
 import com.ruoyi.web.modules.industryservice.mapper.BizYakHerdInventoryMapper;
@@ -37,6 +39,7 @@ import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchDisposab
37 39
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFamilyRanchVo;
38 40
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFarmerHouseholdVo;
39 41
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLargeLivestockFarmerVo;
42
+import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockOwnershipHouseholdVo;
40 43
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockProductOutputVo;
41 44
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchPastureVo;
42 45
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchVaccinationDataVo;
@@ -96,6 +99,9 @@ public class ResearchOpenApiServiceImpl implements IResearchOpenApiService
96 99
     @Autowired
97 100
     private BizVaccinationDataMapper bizVaccinationDataMapper;
98 101
 
102
+    @Autowired
103
+    private BizLivestockOwnershipHouseholdMapper bizLivestockOwnershipHouseholdMapper;
104
+
99 105
     @Override
100 106
     public ResearchTokenVo authenticate(String appKey, String appSecret)
101 107
     {
@@ -403,6 +409,34 @@ public class ResearchOpenApiServiceImpl implements IResearchOpenApiService
403 409
                 rows.stream().map(ResearchOpenApiSupport::toVaccinationDataVo).collect(Collectors.toList()));
404 410
     }
405 411
 
412
+    @Override
413
+    public OpenApiPageResult<ResearchLivestockOwnershipHouseholdVo> listLivestockOwnershipHouseholds(int pageNum,
414
+            int pageSize, Integer statYear, Integer statMonth, String townName, String villageName)
415
+    {
416
+        tokenService.assertEnabled();
417
+        int safePageNum = normalizePageNum(pageNum);
418
+        int safePageSize = normalizePageSize(pageSize);
419
+        BizLivestockOwnershipHousehold query = new BizLivestockOwnershipHousehold();
420
+        query.setStatYear(statYear);
421
+        query.setStatMonth(statMonth);
422
+        if (StringUtils.isNotEmpty(townName))
423
+        {
424
+            query.setTownName(townName.trim());
425
+        }
426
+        if (StringUtils.isNotEmpty(villageName))
427
+        {
428
+            query.setVillageName(villageName.trim());
429
+        }
430
+        // 开放接口无登录上下文,清空 dataScope,避免走填报部门权限
431
+        query.getParams().put("dataScope", "");
432
+        PageHelper.startPage(safePageNum, safePageSize);
433
+        List<BizLivestockOwnershipHousehold> rows =
434
+                bizLivestockOwnershipHouseholdMapper.selectBizLivestockOwnershipHouseholdList(query);
435
+        PageInfo<BizLivestockOwnershipHousehold> page = new PageInfo<>(rows);
436
+        return toPageResult(safePageNum, safePageSize, page.getTotal(),
437
+                rows.stream().map(ResearchOpenApiSupport::toLivestockOwnershipHouseholdVo).collect(Collectors.toList()));
438
+    }
439
+
406 440
     private int normalizePageNum(int pageNum)
407 441
     {
408 442
         return pageNum > 0 ? pageNum : 1;

+ 25 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/research/support/ResearchOpenApiSupport.java

@@ -7,6 +7,7 @@ import com.ruoyi.web.modules.industryservice.domain.BizDisposableIncome;
7 7
 import com.ruoyi.web.modules.industryservice.domain.BizFamilyRanch;
8 8
 import com.ruoyi.web.modules.industryservice.domain.BizFarmerHousehold;
9 9
 import com.ruoyi.web.modules.industryservice.domain.BizLargeLivestockFarmer;
10
+import com.ruoyi.web.modules.industryservice.domain.BizLivestockOwnershipHousehold;
10 11
 import com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput;
11 12
 import com.ruoyi.web.modules.industryservice.domain.BizPasture;
12 13
 import com.ruoyi.web.modules.industryservice.domain.BizVaccinationData;
@@ -20,6 +21,7 @@ import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchDisposab
20 21
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFamilyRanchVo;
21 22
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFarmerHouseholdVo;
22 23
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLargeLivestockFarmerVo;
24
+import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockOwnershipHouseholdVo;
23 25
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockProductOutputVo;
24 26
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchPastureVo;
25 27
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchVaccinationDataVo;
@@ -418,4 +420,27 @@ public final class ResearchOpenApiSupport
418 420
         vo.setImmunityRate(row.getImmunityRate());
419 421
         return vo;
420 422
     }
423
+
424
+    public static ResearchLivestockOwnershipHouseholdVo toLivestockOwnershipHouseholdVo(
425
+            BizLivestockOwnershipHousehold row)
426
+    {
427
+        if (row == null)
428
+        {
429
+            return null;
430
+        }
431
+        ResearchLivestockOwnershipHouseholdVo vo = new ResearchLivestockOwnershipHouseholdVo();
432
+        vo.setOwnershipId(row.getId());
433
+        vo.setStatYear(row.getStatYear());
434
+        vo.setStatMonth(row.getStatMonth());
435
+        vo.setTownName(row.getTownName());
436
+        vo.setVillageName(row.getVillageName());
437
+        vo.setWithLivestockHouseholdCount(row.getWithLivestockHouseholdCount());
438
+        vo.setWithLivestockPopulationCount(row.getWithLivestockPopulationCount());
439
+        vo.setWithLivestockLaborCount(row.getWithLivestockLaborCount());
440
+        vo.setWithLivestockAnimalCount(row.getWithLivestockAnimalCount());
441
+        vo.setWithoutLivestockHouseholdCount(row.getWithoutLivestockHouseholdCount());
442
+        vo.setWithoutLivestockPopulationCount(row.getWithoutLivestockPopulationCount());
443
+        vo.setWithoutLivestockLaborCount(row.getWithoutLivestockLaborCount());
444
+        return vo;
445
+    }
421 446
 }

+ 6 - 0
baqing-admin/src/main/resources/mapper/industryservice/BizLivestockOwnershipHouseholdMapper.xml

@@ -80,6 +80,12 @@
80 80
             <if test="villageDeptId != null">
81 81
                 and r.village_dept_id = #{villageDeptId}
82 82
             </if>
83
+            <if test="townName != null and townName != ''">
84
+                and r.town_name like concat('%', #{townName}, '%')
85
+            </if>
86
+            <if test="villageName != null and villageName != ''">
87
+                and r.village_name like concat('%', #{villageName}, '%')
88
+            </if>
83 89
             ${params.dataScope}
84 90
         </where>
85 91
         order by r.stat_year desc, r.stat_month desc, d.order_num asc, r.village_dept_id asc, r.id desc

+ 30 - 0
baqing-admin/src/test/java/com/ruoyi/web/modules/industryservice/research/controller/ResearchOpenApiControllerApiTest.java

@@ -27,6 +27,7 @@ import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchDisposab
27 27
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFamilyRanchVo;
28 28
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchFarmerHouseholdVo;
29 29
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLargeLivestockFarmerVo;
30
+import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockOwnershipHouseholdVo;
30 31
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchLivestockProductOutputVo;
31 32
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchPastureVo;
32 33
 import com.ruoyi.web.modules.industryservice.research.domain.vo.ResearchVaccinationDataVo;
@@ -372,4 +373,33 @@ class ResearchOpenApiControllerApiTest
372 373
                 .andExpect(jsonPath("$.data.records[0].townName").value("雅安镇"))
373 374
                 .andExpect(jsonPath("$.data.records[0].villageName").value("荣嘎村"));
374 375
     }
376
+
377
+    @Test
378
+    @DisplayName("GET /livestock-ownership-households 成功")
379
+    void listLivestockOwnershipHouseholds() throws Exception
380
+    {
381
+        ResearchLivestockOwnershipHouseholdVo row = new ResearchLivestockOwnershipHouseholdVo();
382
+        row.setOwnershipId(1L);
383
+        row.setStatYear(2026);
384
+        row.setStatMonth(5);
385
+        row.setTownName("雅安镇");
386
+        row.setVillageName("荣嘎村");
387
+        OpenApiPageResult<ResearchLivestockOwnershipHouseholdVo> page = new OpenApiPageResult<>();
388
+        page.setPageNum(1);
389
+        page.setPageSize(20);
390
+        page.setTotal(1L);
391
+        page.setRecords(Collections.singletonList(row));
392
+        when(researchOpenApiService.listLivestockOwnershipHouseholds(anyInt(), anyInt(), any(), any(), any(), any()))
393
+                .thenReturn(page);
394
+
395
+        mockMvc.perform(get("/open-api/v1/research/livestock-ownership-households")
396
+                .param("statYear", "2026")
397
+                .param("statMonth", "5")
398
+                .param("townName", "雅安")
399
+                .param("villageName", "荣嘎"))
400
+                .andExpect(status().isOk())
401
+                .andExpect(jsonPath("$.code").value(200))
402
+                .andExpect(jsonPath("$.data.records[0].townName").value("雅安镇"))
403
+                .andExpect(jsonPath("$.data.records[0].villageName").value("荣嘎村"));
404
+    }
375 405
 }

+ 17 - 0
doc/产业数据模型及服务/科研开放数据接口/科研开放数据接口功能需求.md

@@ -38,6 +38,7 @@
38 38
 | 共同富裕项目列表 | 分页返回共同富裕项目 |
39 39
 | 养殖大户数据列表 | 分页返回养殖大户填报;法人姓名脱敏 |
40 40
 | 疫苗接种数据列表 | 分页返回村级疫苗接种填报 |
41
+| 有无畜户数据列表 | 分页返回村级有无畜户填报 |
41 42
 
42 43
 **本期不实现:**
43 44
 
@@ -264,6 +265,20 @@ sequenceDiagram
264 265
 
265 266
 **不返回**:部门 ID、创建人、备注等内部字段。
266 267
 
268
+### 6.14 有无畜户数据列表
269
+
270
+| 项 | 说明 |
271
+| --- | --- |
272
+| 方法 | GET |
273
+| 路径 | `/livestock-ownership-households` |
274
+| 鉴权 | Bearer Token |
275
+| 分页 | 同 §6.2 |
276
+| 筛选 | `statYear`、`statMonth`、`townName`(乡镇模糊)、`villageName`(村模糊) |
277
+
278
+**返回字段**:`ownershipId`、年月、乡镇村、有畜户/无畜户户数人数劳动力及有畜户牲畜数。
279
+
280
+**不返回**:部门 ID、创建人、备注等内部字段。
281
+
267 282
 ---
268 283
 
269 284
 ## 7. 脱敏规则摘要
@@ -311,6 +326,7 @@ sequenceDiagram
311 326
 | 共同富裕项目管理 | 数据源 `biz_common_prosperity_project` |
312 327
 | 养殖大户数据填报 | 数据源 `biz_large_livestock_farmer` |
313 328
 | 疫苗接种数据填报 | 数据源 `biz_vaccination_data` |
329
+| 有无畜户数据填报 | 数据源 `biz_livestock_ownership_household` |
314 330
 | 若依权限体系 | **无**关联;开放接口走独立 Token |
315 331
 
316 332
 ---
@@ -332,5 +348,6 @@ sequenceDiagram
332 348
 | 共同富裕项目列表 | §6.11 |
333 349
 | 养殖大户列表 | §6.12 |
334 350
 | 疫苗接种列表 | §6.13 |
351
+| 有无畜户列表 | §6.14 |
335 352
 | 脱敏合规 | §7 |
336 353
 | 本期不实现 | §3 |

+ 22 - 2
doc/产业数据模型及服务/科研开放数据接口/科研开放数据接口技术方案.md

@@ -9,7 +9,7 @@
9 9
 | 项 | 说明 |
10 10
 | --- | --- |
11 11
 | **后端** | RuoYi **v3.9.2**(**springboot2** 分支):JDK 8、Spring MVC、MyBatis |
12
-| **数据库** | 只读查询既有表 `biz_pasture`、`biz_yak_asset`、`biz_yak_herd_inventory`、`biz_yak_outbound_report`、`biz_cooperative_development`、`biz_livestock_product_output`、`biz_family_ranch`、`biz_disposable_income`、`biz_farmer_household`、`biz_common_prosperity_project`、`biz_large_livestock_farmer`、`biz_vaccination_data` |
12
+| **数据库** | 只读查询既有表 `biz_pasture`、`biz_yak_asset`、`biz_yak_herd_inventory`、`biz_yak_outbound_report`、`biz_cooperative_development`、`biz_livestock_product_output`、`biz_family_ranch`、`biz_disposable_income`、`biz_farmer_household`、`biz_common_prosperity_project`、`biz_large_livestock_farmer`、`biz_vaccination_data`、`biz_livestock_ownership_household` |
13 13
 | **鉴权** | 独立 JWT + Servlet Filter;`@Anonymous` 绕过若依登录,Filter 校验 Bearer Token |
14 14
 | **响应** | `OpenApiResponse<T>` + `OpenApiPageResult<T>`(与第三方 farming OpenAPI 同结构) |
15 15
 
@@ -260,6 +260,19 @@ Authorization: Bearer <accessToken>
260 260
 
261 261
 实现说明:直接查 `BizVaccinationDataMapper`(清空 `params.dataScope`)。
262 262
 
263
+### 3.14 有无畜户数据列表
264
+
265
+```
266
+GET /open-api/v1/research/livestock-ownership-households?pageNum=1&pageSize=20&statYear=2026&statMonth=5&townName=&villageName=
267
+Authorization: Bearer <accessToken>
268
+```
269
+
270
+**查询参数:** `statYear` / `statMonth`(精确);`townName` / `villageName`(模糊);分页同前。
271
+
272
+**`records[]` 元素(ResearchLivestockOwnershipHouseholdVo):** 有畜户/无畜户统计字段;**不含**部门 ID、操作人、备注。
273
+
274
+实现说明:直接查 `BizLivestockOwnershipHouseholdMapper`(清空 `params.dataScope`)。
275
+
263 276
 ---
264 277
 
265 278
 ## 4. 鉴权流程
@@ -291,8 +304,9 @@ Token 申请:`appKey`/`appSecret` 与配置项精确匹配后签发 JWT(HS51
291 304
 | 共同富裕项目列表 | `BizCommonProsperityProjectMapper.selectBizCommonProsperityProjectList` | `biz_common_prosperity_project` | 项目名模糊;类型/实施年限精确 |
292 305
 | 养殖大户列表 | `BizLargeLivestockFarmerMapper.selectBizLargeLivestockFarmerList` | `biz_large_livestock_farmer` | 年/月精确;乡镇/村/企业名模糊;清空 `params.dataScope` |
293 306
 | 疫苗接种列表 | `BizVaccinationDataMapper.selectBizVaccinationDataList` | `biz_vaccination_data` | 年/月精确;乡镇/村名模糊;清空 `params.dataScope` |
307
+| 有无畜户列表 | `BizLivestockOwnershipHouseholdMapper.selectBizLivestockOwnershipHouseholdList` | `biz_livestock_ownership_household` | 年/月精确;乡镇/村名模糊;清空 `params.dataScope` |
294 308
 
295
-实体 → VO:`ResearchOpenApiSupport.toPastureVo` / `toYakAssetVo` / `toYakHerdInventoryVo` / `toYakOutboundReportVo` / `toCooperativeDevelopmentVo` / `toLivestockProductOutputVo` / `toFamilyRanchVo` / `toDisposableIncomeVo` / `toFarmerHouseholdVo` / `toCommonProsperityProjectVo` / `toLargeLivestockFarmerVo` / `toVaccinationDataVo`。
309
+实体 → VO:`ResearchOpenApiSupport.toPastureVo` / `toYakAssetVo` / `toYakHerdInventoryVo` / `toYakOutboundReportVo` / `toCooperativeDevelopmentVo` / `toLivestockProductOutputVo` / `toFamilyRanchVo` / `toDisposableIncomeVo` / `toFarmerHouseholdVo` / `toCommonProsperityProjectVo` / `toLargeLivestockFarmerVo` / `toVaccinationDataVo` / `toLivestockOwnershipHouseholdVo`
296 310
 
297 311
 ---
298 312
 
@@ -377,6 +391,10 @@ curl "http://localhost:8010/open-api/v1/research/large-livestock-farmers?pageNum
377 391
 # 13. 疫苗接种
378 392
 curl "http://localhost:8010/open-api/v1/research/vaccination-data?pageNum=1&pageSize=10&statYear=2026&townName=雅安" \
379 393
   -H "Authorization: Bearer <accessToken>"
394
+
395
+# 14. 有无畜户
396
+curl "http://localhost:8010/open-api/v1/research/livestock-ownership-households?pageNum=1&pageSize=10&statYear=2026&townName=雅安" \
397
+  -H "Authorization: Bearer <accessToken>"
380 398
 ```
381 399
 
382 400
 ---
@@ -408,6 +426,7 @@ curl "http://localhost:8010/open-api/v1/research/vaccination-data?pageNum=1&page
408 426
 | §6.11 共同富裕项目 | **§3.11**、**§5** BizCommonProsperityProject |
409 427
 | §6.12 养殖大户 | **§3.12**、**§5** BizLargeLivestockFarmer |
410 428
 | §6.13 疫苗接种 | **§3.13**、**§5** BizVaccinationData |
429
+| §6.14 有无畜户 | **§3.14**、**§5** BizLivestockOwnershipHousehold |
411 430
 | §7 脱敏 | **§6** Masking |
412 431
 | §3 不实现机构区分 | 单一 app-key/secret,JWT 无 clientId |
413 432
 
@@ -417,6 +436,7 @@ curl "http://localhost:8010/open-api/v1/research/vaccination-data?pageNum=1&page
417 436
 
418 437
 | 版本 | 日期 | 说明 |
419 438
 | --- | --- | --- |
439
+| 1.11 | 2026-07-22 | 新增有无畜户开放列表(年/月/乡镇村模糊+分页) |
420 440
 | 1.10 | 2026-07-22 | 新增疫苗接种开放列表(年/月/乡镇村模糊+分页) |
421 441
 | 1.9 | 2026-07-22 | 新增养殖大户开放列表(年/月/乡镇村/企业名模糊+分页;法人脱敏) |
422 442
 | 1.8 | 2026-07-22 | 新增共同富裕项目开放列表(项目名模糊/类型与实施年限精确+分页) |

+ 5 - 1
doc/产业数据模型及服务/科研开放数据接口/科研开放数据接口测试用例.md

@@ -63,6 +63,8 @@
63 63
 | KYKF-API-030 | 养殖大户 | 年/月/乡镇村/企业名筛选 | 接口测试 | curl | §6.12 | 已知企业名片段 | GET 带筛选参数 | 条件生效;名称模糊匹配 |
64 64
 | KYKF-API-031 | 疫苗接种 | 分页列表 | 接口测试 | curl | §6.13 | 有效 Token;库有接种数据 | GET `/vaccination-data?pageNum=1&pageSize=10` | `code=200`;无部门 ID |
65 65
 | KYKF-API-032 | 疫苗接种 | 年/月/乡镇村筛选 | 接口测试 | curl | §6.13 | 已知年月与乡镇名片段 | GET 带筛选参数 | 条件生效;名称模糊匹配 |
66
+| KYKF-API-033 | 有无畜户 | 分页列表 | 接口测试 | curl | §6.14 | 有效 Token;库有畜户数据 | GET `/livestock-ownership-households?pageNum=1&pageSize=10` | `code=200`;无部门 ID |
67
+| KYKF-API-034 | 有无畜户 | 年/月/乡镇村筛选 | 接口测试 | curl | §6.14 | 已知年月与乡镇名片段 | GET 带筛选参数 | 条件生效;名称模糊匹配 |
66 68
 
67 69
 ---
68 70
 
@@ -83,11 +85,12 @@
83 85
 | §6.11 共同富裕项目列表 | — | API-027~028 |
84 86
 | §6.12 养殖大户列表 | — | API-029~030 |
85 87
 | §6.13 疫苗接种列表 | — | API-031~032 |
88
+| §6.14 有无畜户列表 | — | API-033~034 |
86 89
 | §7 脱敏 | UT-001~004 | API-012 |
87 90
 | §2 分页 | — | API-010 |
88 91
 | §3 无机构区分 | UT-005 | API-001(单一凭证) |
89 92
 
90
-**用例统计**:单元 **6**、接口 **32**,合计 **38** 条。
93
+**用例统计**:单元 **6**、接口 **34**,合计 **40** 条。
91 94
 
92 95
 ---
93 96
 
@@ -112,6 +115,7 @@ curl -s "$BASE/farmer-households?pageNum=1&pageSize=5&statYear=2026" -H "Authori
112 115
 curl -s "$BASE/common-prosperity-projects?pageNum=1&pageSize=5&implYear=2025" -H "Authorization: Bearer $TOKEN"
113 116
 curl -s "$BASE/large-livestock-farmers?pageNum=1&pageSize=5&statYear=2026" -H "Authorization: Bearer $TOKEN"
114 117
 curl -s "$BASE/vaccination-data?pageNum=1&pageSize=5&statYear=2026" -H "Authorization: Bearer $TOKEN"
118
+curl -s "$BASE/livestock-ownership-households?pageNum=1&pageSize=5&statYear=2026" -H "Authorization: Bearer $TOKEN"
115 119
 ```
116 120
 
117 121
 (Windows 环境可用 PowerShell `Invoke-RestMethod`,见技术方案 **§8**。)