wwh 1 nedēļu atpakaļ
vecāks
revīzija
59f1251c31

+ 26 - 9
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/domain/BizGrassland.java

@@ -24,33 +24,30 @@ public class BizGrassland extends BaseEntity
24 24
     @NotNull(message = "面积不能为空")
25 25
     private BigDecimal areaMu;
26 26
 
27
-    @NotNull(message = "退化等级不能为空")
27
+    /** 禁牧面积(亩),选填 */
28
+    private BigDecimal grazingBanArea;
29
+
30
+    /** 草畜平衡面积(亩),选填 */
31
+    private BigDecimal grassBalanceArea;
32
+
28 33
     private Integer degradationLevel;
29 34
 
30
-    @NotNull(message = "利用类型不能为空")
31 35
     private Integer utilizationType;
32 36
 
33
-    @NotNull(message = "亩产草量不能为空")
34 37
     private BigDecimal grassYieldPerMu;
35 38
 
36
-    @NotNull(message = "利用率不能为空")
37 39
     private BigDecimal utilizationRate;
38 40
 
39
-    @NotNull(message = "禁牧开始日期不能为空")
40 41
     @JsonFormat(pattern = "yyyy-MM-dd")
41 42
     private Date grazingBanStartDate;
42 43
 
43
-    @NotNull(message = "禁牧结束日期不能为空")
44 44
     @JsonFormat(pattern = "yyyy-MM-dd")
45 45
     private Date grazingBanEndDate;
46 46
 
47
-    @NotNull(message = "轮牧小区数量不能为空")
48 47
     private Integer rotationPlotCount;
49 48
 
50
-    @NotNull(message = "小区放牧天数不能为空")
51 49
     private Integer rotationGrazingDays;
52 50
 
53
-    @NotNull(message = "轮牧周期不能为空")
54 51
     private Integer rotationCycleDays;
55 52
 
56 53
     /** 0 存在 2 删除 */
@@ -89,6 +86,26 @@ public class BizGrassland extends BaseEntity
89 86
         this.areaMu = areaMu;
90 87
     }
91 88
 
89
+    public BigDecimal getGrazingBanArea()
90
+    {
91
+        return grazingBanArea;
92
+    }
93
+
94
+    public void setGrazingBanArea(BigDecimal grazingBanArea)
95
+    {
96
+        this.grazingBanArea = grazingBanArea;
97
+    }
98
+
99
+    public BigDecimal getGrassBalanceArea()
100
+    {
101
+        return grassBalanceArea;
102
+    }
103
+
104
+    public void setGrassBalanceArea(BigDecimal grassBalanceArea)
105
+    {
106
+        this.grassBalanceArea = grassBalanceArea;
107
+    }
108
+
92 109
     public Integer getDegradationLevel()
93 110
     {
94 111
         return degradationLevel;

+ 55 - 13
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/support/GrasslandValidation.java

@@ -7,7 +7,7 @@ import com.ruoyi.common.utils.StringUtils;
7 7
 import com.ruoyi.web.modules.industryservice.domain.BizGrassland;
8 8
 
9 9
 /**
10
- * 草场管理入参校验。
10
+ * 草场管理入参校验。除草场名称、面积外均为选填;有值时校验格式与区间。
11 11
  */
12 12
 public final class GrasslandValidation
13 13
 {
@@ -46,8 +46,11 @@ public final class GrasslandValidation
46 46
 
47 47
     public static void validateDegradationLevel(Integer degradationLevel)
48 48
     {
49
-        if (degradationLevel == null
50
-                || degradationLevel < GrasslandRules.DEGRADATION_NONE
49
+        if (degradationLevel == null)
50
+        {
51
+            return;
52
+        }
53
+        if (degradationLevel < GrasslandRules.DEGRADATION_NONE
51 54
                 || degradationLevel > GrasslandRules.DEGRADATION_EXTREME)
52 55
         {
53 56
             throw new ServiceException("退化等级须为1~5(1未退化5极重度)");
@@ -56,8 +59,11 @@ public final class GrasslandValidation
56 59
 
57 60
     public static void validateUtilizationType(Integer utilizationType)
58 61
     {
59
-        if (utilizationType == null
60
-                || utilizationType < GrasslandRules.UTILIZATION_BAN
62
+        if (utilizationType == null)
63
+        {
64
+            return;
65
+        }
66
+        if (utilizationType < GrasslandRules.UTILIZATION_BAN
61 67
                 || utilizationType > GrasslandRules.UTILIZATION_YEAR_ROUND)
62 68
         {
63 69
             throw new ServiceException("利用类型须为1~3(1禁牧2轮牧3全年放牧)");
@@ -72,9 +78,25 @@ public final class GrasslandValidation
72 78
         }
73 79
     }
74 80
 
81
+    public static void validateOptionalPositiveArea(BigDecimal area, String fieldLabel)
82
+    {
83
+        if (area == null)
84
+        {
85
+            return;
86
+        }
87
+        if (area.compareTo(ZERO) <= 0)
88
+        {
89
+            throw new ServiceException(fieldLabel + "须为大于0的数字(亩)");
90
+        }
91
+    }
92
+
75 93
     public static void validateGrassYieldPerMu(BigDecimal grassYieldPerMu)
76 94
     {
77
-        if (grassYieldPerMu == null || grassYieldPerMu.compareTo(ZERO) <= 0)
95
+        if (grassYieldPerMu == null)
96
+        {
97
+            return;
98
+        }
99
+        if (grassYieldPerMu.compareTo(ZERO) <= 0)
78 100
         {
79 101
             throw new ServiceException("亩产草量须为大于0的数字(kg/亩)");
80 102
         }
@@ -82,9 +104,11 @@ public final class GrasslandValidation
82 104
 
83 105
     public static void validateUtilizationRate(BigDecimal utilizationRate)
84 106
     {
85
-        if (utilizationRate == null
86
-                || utilizationRate.compareTo(ZERO) < 0
87
-                || utilizationRate.compareTo(ONE) > 0)
107
+        if (utilizationRate == null)
108
+        {
109
+            return;
110
+        }
111
+        if (utilizationRate.compareTo(ZERO) < 0 || utilizationRate.compareTo(ONE) > 0)
88 112
         {
89 113
             throw new ServiceException("利用率须在0~1之间");
90 114
         }
@@ -92,9 +116,13 @@ public final class GrasslandValidation
92 116
 
93 117
     public static void validateGrazingBanDates(Date start, Date end)
94 118
     {
119
+        if (start == null && end == null)
120
+        {
121
+            return;
122
+        }
95 123
         if (start == null || end == null)
96 124
         {
97
-            throw new ServiceException("禁牧开始、结束日期不能为空");
125
+            throw new ServiceException("禁牧开始、结束日期须同时填写或同时留空");
98 126
         }
99 127
         if (start.after(end))
100 128
         {
@@ -104,7 +132,11 @@ public final class GrasslandValidation
104 132
 
105 133
     public static void validateRotationPlotCount(Integer rotationPlotCount)
106 134
     {
107
-        if (rotationPlotCount == null || rotationPlotCount < 1)
135
+        if (rotationPlotCount == null)
136
+        {
137
+            return;
138
+        }
139
+        if (rotationPlotCount < 1)
108 140
         {
109 141
             throw new ServiceException("轮牧小区数量须为大于等于1的整数(块)");
110 142
         }
@@ -112,7 +144,11 @@ public final class GrasslandValidation
112 144
 
113 145
     public static void validateRotationGrazingDays(Integer rotationGrazingDays)
114 146
     {
115
-        if (rotationGrazingDays == null || rotationGrazingDays < 1)
147
+        if (rotationGrazingDays == null)
148
+        {
149
+            return;
150
+        }
151
+        if (rotationGrazingDays < 1)
116 152
         {
117 153
             throw new ServiceException("小区放牧天数须为大于等于1的整数(天)");
118 154
         }
@@ -120,7 +156,11 @@ public final class GrasslandValidation
120 156
 
121 157
     public static void validateRotationCycleDays(Integer rotationCycleDays)
122 158
     {
123
-        if (rotationCycleDays == null || rotationCycleDays < 1)
159
+        if (rotationCycleDays == null)
160
+        {
161
+            return;
162
+        }
163
+        if (rotationCycleDays < 1)
124 164
         {
125 165
             throw new ServiceException("轮牧周期须为大于等于1的整数(天)");
126 166
         }
@@ -139,6 +179,8 @@ public final class GrasslandValidation
139 179
         trimFieldsForSave(row);
140 180
         validateGrasslandName(row.getGrasslandName());
141 181
         validateAreaMu(row.getAreaMu());
182
+        validateOptionalPositiveArea(row.getGrazingBanArea(), "禁牧面积");
183
+        validateOptionalPositiveArea(row.getGrassBalanceArea(), "草畜平衡面积");
142 184
         validateDegradationLevel(row.getDegradationLevel());
143 185
         validateUtilizationType(row.getUtilizationType());
144 186
         validateGrassYieldPerMu(row.getGrassYieldPerMu());

+ 10 - 3
baqing-admin/src/main/resources/mapper/industryservice/BizGrasslandMapper.xml

@@ -6,6 +6,8 @@
6 6
         <id     property="id"                    column="id"/>
7 7
         <result property="grasslandName"         column="grassland_name"/>
8 8
         <result property="areaMu"                column="area_mu"/>
9
+        <result property="grazingBanArea"        column="grazing_ban_area"/>
10
+        <result property="grassBalanceArea"      column="grass_balance_area"/>
9 11
         <result property="degradationLevel"      column="degradation_level"/>
10 12
         <result property="utilizationType"       column="utilization_type"/>
11 13
         <result property="grassYieldPerMu"       column="grass_yield_per_mu"/>
@@ -24,7 +26,8 @@
24 26
     </resultMap>
25 27
 
26 28
     <sql id="selectVo">
27
-        select id, grassland_name, area_mu, degradation_level, utilization_type,
29
+        select id, grassland_name, area_mu, grazing_ban_area, grass_balance_area,
30
+               degradation_level, utilization_type,
28 31
                grass_yield_per_mu, utilization_rate,
29 32
                grazing_ban_start_date, grazing_ban_end_date,
30 33
                rotation_plot_count, rotation_grazing_days, rotation_cycle_days,
@@ -61,13 +64,15 @@
61 64
 
62 65
     <insert id="insertBizGrassland" parameterType="com.ruoyi.web.modules.industryservice.domain.BizGrassland" useGeneratedKeys="true" keyProperty="id">
63 66
         insert into biz_grassland (
64
-            grassland_name, area_mu, degradation_level, utilization_type,
67
+            grassland_name, area_mu, grazing_ban_area, grass_balance_area,
68
+            degradation_level, utilization_type,
65 69
             grass_yield_per_mu, utilization_rate,
66 70
             grazing_ban_start_date, grazing_ban_end_date,
67 71
             rotation_plot_count, rotation_grazing_days, rotation_cycle_days,
68 72
             del_flag, create_by, create_time, remark
69 73
         ) values (
70
-            #{grasslandName}, #{areaMu}, #{degradationLevel}, #{utilizationType},
74
+            #{grasslandName}, #{areaMu}, #{grazingBanArea}, #{grassBalanceArea},
75
+            #{degradationLevel}, #{utilizationType},
71 76
             #{grassYieldPerMu}, #{utilizationRate},
72 77
             #{grazingBanStartDate}, #{grazingBanEndDate},
73 78
             #{rotationPlotCount}, #{rotationGrazingDays}, #{rotationCycleDays},
@@ -79,6 +84,8 @@
79 84
         update biz_grassland set
80 85
             grassland_name = #{grasslandName},
81 86
             area_mu = #{areaMu},
87
+            grazing_ban_area = #{grazingBanArea},
88
+            grass_balance_area = #{grassBalanceArea},
82 89
             degradation_level = #{degradationLevel},
83 90
             utilization_type = #{utilizationType},
84 91
             grass_yield_per_mu = #{grassYieldPerMu},

+ 29 - 9
baqing-admin/src/test/java/com/ruoyi/web/modules/industryservice/support/GrasslandValidationTest.java

@@ -41,43 +41,52 @@ class GrasslandValidationTest
41 41
     }
42 42
 
43 43
     @Test
44
-    @DisplayName("ZCZX-CCGL-UT-003 退化等级枚举")
44
+    @DisplayName("ZCZX-CCGL-UT-003 退化等级枚举(选填)")
45 45
     void ut003_degradationLevel()
46 46
     {
47
+        assertDoesNotThrow(() -> GrasslandValidation.validateDegradationLevel(null));
47 48
         assertDoesNotThrow(() -> GrasslandValidation.validateDegradationLevel(GrasslandRules.DEGRADATION_NONE));
48 49
         assertDoesNotThrow(() -> GrasslandValidation.validateDegradationLevel(GrasslandRules.DEGRADATION_EXTREME));
49 50
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateDegradationLevel(0));
50 51
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateDegradationLevel(6));
51
-        assertThrows(ServiceException.class, () -> GrasslandValidation.validateDegradationLevel(null));
52 52
     }
53 53
 
54 54
     @Test
55
-    @DisplayName("ZCZX-CCGL-UT-004 利用类型枚举")
55
+    @DisplayName("ZCZX-CCGL-UT-004 利用类型枚举(选填)")
56 56
     void ut004_utilizationType()
57 57
     {
58
+        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationType(null));
58 59
         assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationType(GrasslandRules.UTILIZATION_BAN));
59 60
         assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationType(GrasslandRules.UTILIZATION_YEAR_ROUND));
60 61
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateUtilizationType(0));
61 62
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateUtilizationType(4));
62
-        assertThrows(ServiceException.class, () -> GrasslandValidation.validateUtilizationType(null));
63 63
     }
64 64
 
65 65
     @Test
66
-    @DisplayName("ZCZX-CCGL-UT-005 面积/亩产草量")
66
+    @DisplayName("ZCZX-CCGL-UT-005 面积/亩产草量/禁牧与草畜平衡面积")
67 67
     void ut005_areaAndYield()
68 68
     {
69 69
         assertDoesNotThrow(() -> GrasslandValidation.validateAreaMu(new BigDecimal("100.5")));
70 70
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateAreaMu(BigDecimal.ZERO));
71 71
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateAreaMu(new BigDecimal("-1")));
72 72
 
73
+        assertDoesNotThrow(() -> GrasslandValidation.validateGrassYieldPerMu(null));
73 74
         assertDoesNotThrow(() -> GrasslandValidation.validateGrassYieldPerMu(new BigDecimal("350")));
74 75
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrassYieldPerMu(BigDecimal.ZERO));
76
+
77
+        assertDoesNotThrow(() -> GrasslandValidation.validateOptionalPositiveArea(null, "禁牧面积"));
78
+        assertDoesNotThrow(() -> GrasslandValidation.validateOptionalPositiveArea(new BigDecimal("10"), "禁牧面积"));
79
+        assertThrows(ServiceException.class,
80
+                () -> GrasslandValidation.validateOptionalPositiveArea(BigDecimal.ZERO, "禁牧面积"));
81
+        assertThrows(ServiceException.class,
82
+                () -> GrasslandValidation.validateOptionalPositiveArea(new BigDecimal("-1"), "草畜平衡面积"));
75 83
     }
76 84
 
77 85
     @Test
78
-    @DisplayName("ZCZX-CCGL-UT-006 利用率区间")
86
+    @DisplayName("ZCZX-CCGL-UT-006 利用率区间(选填)")
79 87
     void ut006_utilizationRate()
80 88
     {
89
+        assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(null));
81 90
         assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(BigDecimal.ZERO));
82 91
         assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(BigDecimal.ONE));
83 92
         assertDoesNotThrow(() -> GrasslandValidation.validateUtilizationRate(new BigDecimal("0.65")));
@@ -86,21 +95,24 @@ class GrasslandValidationTest
86 95
     }
87 96
 
88 97
     @Test
89
-    @DisplayName("ZCZX-CCGL-UT-007 禁牧日期区间")
98
+    @DisplayName("ZCZX-CCGL-UT-007 禁牧日期区间(选填成对)")
90 99
     void ut007_grazingBanDates()
91 100
     {
92 101
         Date start = Date.valueOf("2025-01-01");
93 102
         Date end = Date.valueOf("2025-03-31");
103
+        assertDoesNotThrow(() -> GrasslandValidation.validateGrazingBanDates(null, null));
94 104
         assertDoesNotThrow(() -> GrasslandValidation.validateGrazingBanDates(start, end));
95 105
         assertThrows(ServiceException.class,
96 106
                 () -> GrasslandValidation.validateGrazingBanDates(Date.valueOf("2025-04-01"), end));
97 107
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrazingBanDates(start, null));
108
+        assertThrows(ServiceException.class, () -> GrasslandValidation.validateGrazingBanDates(null, end));
98 109
     }
99 110
 
100 111
     @Test
101
-    @DisplayName("ZCZX-CCGL-UT-008 轮牧三项整数")
112
+    @DisplayName("ZCZX-CCGL-UT-008 轮牧三项整数(选填)")
102 113
     void ut008_rotationParams()
103 114
     {
115
+        assertDoesNotThrow(() -> GrasslandValidation.validateRotationPlotCount(null));
104 116
         assertDoesNotThrow(() -> GrasslandValidation.validateRotationPlotCount(1));
105 117
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateRotationPlotCount(0));
106 118
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateRotationGrazingDays(0));
@@ -108,10 +120,14 @@ class GrasslandValidationTest
108 120
     }
109 121
 
110 122
     @Test
111
-    @DisplayName("ZCZX-CCGL-UT-009 全量保存校验")
123
+    @DisplayName("ZCZX-CCGL-UT-009 全量保存校验(仅名称+面积必填)")
112 124
     void ut009_validateRowForSave()
113 125
     {
114 126
         assertDoesNotThrow(() -> GrasslandValidation.validateRowForSave(sampleRow()));
127
+        BizGrassland minimal = new BizGrassland();
128
+        minimal.setGrasslandName("最小草场");
129
+        minimal.setAreaMu(new BigDecimal("1"));
130
+        assertDoesNotThrow(() -> GrasslandValidation.validateRowForSave(minimal));
115 131
         BizGrassland bad = sampleRow();
116 132
         bad.setUtilizationRate(new BigDecimal("2"));
117 133
         assertThrows(ServiceException.class, () -> GrasslandValidation.validateRowForSave(bad));
@@ -127,6 +143,8 @@ class GrasslandValidationTest
127 143
         assertTrue(xml.contains("id desc"));
128 144
         assertTrue(xml.contains("del_flag = '0'"));
129 145
         assertTrue(xml.contains("del_flag = '2'"));
146
+        assertTrue(xml.contains("grazing_ban_area"));
147
+        assertTrue(xml.contains("grass_balance_area"));
130 148
     }
131 149
 
132 150
     private static BizGrassland sampleRow()
@@ -134,6 +152,8 @@ class GrasslandValidationTest
134 152
         BizGrassland r = new BizGrassland();
135 153
         r.setGrasslandName("示范草场");
136 154
         r.setAreaMu(new BigDecimal("100.5"));
155
+        r.setGrazingBanArea(new BigDecimal("30"));
156
+        r.setGrassBalanceArea(new BigDecimal("70.5"));
137 157
         r.setDegradationLevel(GrasslandRules.DEGRADATION_NONE);
138 158
         r.setUtilizationType(GrasslandRules.UTILIZATION_ROTATION);
139 159
         r.setGrassYieldPerMu(new BigDecimal("350"));

+ 6 - 4
doc/产业数据模型及服务/草场管理/草场管理前端技术方案.md

@@ -37,7 +37,7 @@
37 37
 ## 3. 页面结构
38 38
 
39 39
 1. **筛选区**(`el-card`):草场名称关键字(模糊)、利用类型、退化等级;搜索、重置、新增、批量删除、导出。  
40
-2. **列表区**(`el-card`):宽表横向滚动;列含名称、面积、退化等级、利用类型、亩产草量、利用率(%)、禁牧起止、轮牧三项、创建时间。  
40
+2. **列表区**(`el-card`):宽表横向滚动;列含名称、面积、禁牧面积、草畜平衡面积、退化等级、利用类型、亩产草量、利用率(%)、禁牧起止、轮牧三项、创建时间。  
41 41
 3. **新增/编辑弹窗**(900px,两列):全部业务字段 + 备注;数值带单位(亩、kg/亩、0~1、块、天)。  
42 42
 4. **查看弹窗**:只读 + 审计字段。  
43 43
 
@@ -68,7 +68,8 @@
68 68
 
69 69
 ## 6. 校验与交互要点
70 70
 
71
-- 草场名称 1~10 字;面积、亩产草量 > 0;利用率 0~1;禁牧结束 ≥ 开始;轮牧三项为 ≥1 的整数。  
71
+- **必填**:草场名称 1~10 字;面积 > 0。  
72
+- **选填**(有值时校验):禁牧面积、草畜平衡面积 > 0;亩产草量 > 0;利用率 0~1;禁牧结束 ≥ 开始且成对;轮牧三项为 ≥1 的整数。  
72 73
 - 备注选填 ≤100 字。  
73 74
 - 不因利用类型隐藏字段(与功能需求 §5.1 一致)。  
74 75
 - 删除为逻辑删除,前端仅调 DELETE 接口。  
@@ -77,9 +78,9 @@
77 78
 
78 79
 ## 7. 联调说明
79 80
 
80
-1. 后端实现 `草场管理技术方案.md` §3 及 `biz_grassland` 表。  
81
+1. 后端实现 `草场管理技术方案.md` §3 及 `biz_grassland` 表(升级脚本 `biz_grassland_fields_alter.sql`)
81 82
 2. 配置菜单与六项按钮权限。  
82
-3. 验证:筛选、全字段 CRUD、导出、日期与利用率边界。  
83
+3. 验证:筛选、仅名称+面积新增、全字段 CRUD、日期与利用率边界。  
83 84
 
84 85
 ---
85 86
 
@@ -88,3 +89,4 @@
88 89
 | 版本 | 说明 |
89 90
 | --- | --- |
90 91
 | 1.0 | 初版:双卡片 + 宽表 CRUD;无地图标点 |
92
+| 1.1 | 禁牧面积、草畜平衡面积;非名称/面积字段改为选填 |

+ 34 - 30
doc/产业数据模型及服务/草场管理/草场管理功能需求.md

@@ -48,25 +48,27 @@
48 48
 
49 49
 | 字段 | 业务含义 |
50 50
 | --- | --- |
51
-| 面积 | 草场范围对应的土地面积,单位为**亩** |
52
-| 亩产草量 | 单位面积产草量,单位为 **kg/亩**,用于评估草场生产力 |
53
-| 利用率 | 草场可利用程度或利用强度系数,取 **0~1**,数值越大表示利用程度越高(具体统计口径若与行业标准不一致,须在评审时固化) |
54
-| 禁牧开始/结束日期 | 本条记录所对应的**禁牧或休牧时段**(起止日均必填,且开始日不得晚于结束日) |
55
-| 轮牧小区数量 | 轮牧划分的小区(地块)个数,单位为**块** |
56
-| 小区放牧天数 | 每个小区单次连续放牧天数,单位为**天** |
57
-| 轮牧周期 | 完成一轮轮牧所需周期,单位为**天** |
58
-
59
-> **说明:** 界面新增表单中上述指标均为必填(见 **§5.1**)。不同「利用类型」下各指标的业务侧重点不同(见 **§2.5**),但本期不因利用类型而隐藏或豁免必填校验,除非产品另行评审变更。
51
+| 面积 | 草场范围对应的土地面积,单位为**亩**(**必填**) |
52
+| 禁牧面积 | 纳入禁牧管理的面积,单位为**亩**(选填;有值须大于 0) |
53
+| 草畜平衡面积 | 纳入草畜平衡管理的面积,单位为**亩**(选填;有值须大于 0) |
54
+| 亩产草量 | 单位面积产草量,单位为 **kg/亩**,用于评估草场生产力(选填) |
55
+| 利用率 | 草场可利用程度或利用强度系数,取 **0~1**,数值越大表示利用程度越高(选填) |
56
+| 禁牧开始/结束日期 | 本条记录所对应的**禁牧或休牧时段**(选填;若填写须起止成对,且开始日不得晚于结束日) |
57
+| 轮牧小区数量 | 轮牧划分的小区(地块)个数,单位为**块**(选填) |
58
+| 小区放牧天数 | 每个小区单次连续放牧天数,单位为**天**(选填) |
59
+| 轮牧周期 | 完成一轮轮牧所需周期,单位为**天**(选填) |
60
+
61
+> **说明:** 界面新增/修改表单中,**仅草场名称、面积为必填**,其余业务字段均为选填;有值时仍执行对应格式与区间校验(见 **§5.1**)。不同「利用类型」下各指标的业务侧重点不同(见 **§2.5**)。
60 62
 
61 63
 ### 2.5 利用类型与字段的业务侧重(逻辑说明)
62 64
 
63 65
 | 利用类型 | 业务侧重(需求层理解) |
64 66
 | --- | --- |
65
-| **禁牧** | 「禁牧开始/结束日期」为核心管控信息;轮牧相关指标仍须填报,用于台账完整性与后续类型变更,宜按实际规划或历史轮牧参数填写 |
67
+| **禁牧** | 「禁牧开始/结束日期」「禁牧面积」为核心管控信息;轮牧相关指标可按实际规划或历史参数选填 |
66 68
 | **轮牧** | 「轮牧小区数量」「小区放牧天数」「轮牧周期」为核心管控信息;禁牧日期可表示休牧窗口或禁牧补段 |
67 69
 | **全年放牧** | 强调全年可利用;禁牧日期可表示季节性休牧或临时禁牧段;轮牧指标可填「等效」或历史参数,具体填报口径由县级业务规范约定 |
68 70
 
69
-若后续产品要求「按利用类型动态显隐字段、仅校验相关项」,须单独修订 **§5.1** 并更新界面原型。
71
+本期不因利用类型动态显隐字段或强制相关项必填;若后续产品要求「按利用类型动态显隐字段、仅校验相关项」,须单独修订 **§5.1** 并更新界面原型。
70 72
 
71 73
 ---
72 74
 
@@ -75,7 +77,7 @@
75 77
 **本期实现:**
76 78
 
77 79
 - 草场的新增、修改、逻辑删除、分页列表查询、详情查看  
78
-- 草场名称、面积、退化等级、利用类型、产草与利用指标、禁牧时段、轮牧参数、备注的录入与校验  
80
+- 草场名称、面积、禁牧面积、草畜平衡面积、退化等级、利用类型、产草与利用指标、禁牧时段、轮牧参数、备注的录入与校验  
79 81
 - 按草场名称关键字、利用类型的列表筛选  
80 82
 - 列表操作:查看、编辑、删除;**不含**地图标点  
81 83
 
@@ -115,23 +117,25 @@ flowchart LR
115 117
 | --- | --- |
116 118
 | 草场名称 | **必填**;长度 **1~10** 个字符(与界面「限 10 字」一致;字符计数与项目全局一致) |
117 119
 | 面积 | **必填**;**数字**;单位为**亩**;须为**正数**(大于 0);小数位数与项目数字输入规范一致 |
118
-| 退化等级 | **必填**;**单选**,取值见 **§2.1**(未退化 / 轻度 / 中度 / 重度 / 极重度) |
119
-| 利用类型 | **必填**;**单选**,取值见 **§2.2**(禁牧 / 轮牧 / 全年放牧) |
120
-| 亩产草量 | **必填**;**正数**;单位为 **kg/亩** |
121
-| 利用率 | **必填**;**数字**;取值区间 **0~1**(闭区间,含 0 与 1) |
122
-| 禁牧开始日期 | **必填**;日期格式 **YYYY-MM-DD** |
123
-| 禁牧结束日期 | **必填**;日期格式 **YYYY-MM-DD**;**不得早于**禁牧开始日期 |
124
-| 轮牧小区数量 | **必填**;**正整数**(≥ 1);单位为**块** |
125
-| 小区放牧天数 | **必填**;**正整数**(≥ 1);单位为**天** |
126
-| 轮牧周期 | **必填**;**正整数**(≥ 1);单位为**天** |
120
+| 禁牧面积 | **选填**;若有值须为**正数**(大于 0);单位为**亩** |
121
+| 草畜平衡面积 | **选填**;若有值须为**正数**(大于 0);单位为**亩** |
122
+| 退化等级 | **选填**;**单选**,取值见 **§2.1**(未退化 / 轻度 / 中度 / 重度 / 极重度) |
123
+| 利用类型 | **选填**;**单选**,取值见 **§2.2**(禁牧 / 轮牧 / 全年放牧) |
124
+| 亩产草量 | **选填**;若有值须为**正数**;单位为 **kg/亩** |
125
+| 利用率 | **选填**;若有值须为**数字**;取值区间 **0~1**(闭区间,含 0 与 1) |
126
+| 禁牧开始日期 | **选填**;日期格式 **YYYY-MM-DD**;与结束日期须同时有值或同时为空 |
127
+| 禁牧结束日期 | **选填**;日期格式 **YYYY-MM-DD**;有值时**不得早于**禁牧开始日期 |
128
+| 轮牧小区数量 | **选填**;若有值须为**正整数**(≥ 1);单位为**块** |
129
+| 小区放牧天数 | **选填**;若有值须为**正整数**(≥ 1);单位为**天** |
130
+| 轮牧周期 | **选填**;若有值须为**正整数**(≥ 1);单位为**天** |
127 131
 | 备注 | **选填**;若有内容,长度不超过 **100** 个字符 |
128 132
 
129
-**必填字段汇总:** 除备注外,上表所列字段均为必填。
133
+**必填字段汇总:** 仅「草场名称」「面积」必填;其余均为选填。
130 134
 
131 135
 **联动与校验:**
132 136
 
133
-- 禁牧开始日期、禁牧结束日期须成对有效;仅填其一视为不完整,不允许提交。  
134
-- 面积、亩产草量、利用率、轮牧相关数值须拒绝非数字、负数、零(面积与亩产草量、轮牧整数项)及超出区间的利用率
137
+- 禁牧开始日期、禁牧结束日期须成对有效(同时有值或同时为空);仅填其一视为不完整,不允许提交。  
138
+- 面积及有值的禁牧面积、草畜平衡面积、亩产草量须拒绝非数字、负数、零;有值的利用率须在 0~1;有值的轮牧整数项须 ≥ 1
135 139
 - 各字段校验失败时须给出**可区分**的错误提示(如名称超长、日期区间颠倒、利用率超界等)。  
136 140
 - 若业务要求「草场名称」在管辖范围内唯一,须在评审时单独约定并写入本节。  
137 141
 - 「轮牧周期」与「轮牧小区数量 × 小区放牧天数」是否存在固定换算关系,本期**不强制**等式校验;若县级规范有公式要求,评审通过后补充至本节。
@@ -148,16 +152,16 @@ flowchart LR
148 152
 - **排序:** 默认按 **创建时间倒序**(最新登记在前);相同时间下次要排序键与项目列表规范一致(若有)。  
149 153
 - **重置:** 支持一键清空查询条件并恢复默认列表(与界面「重置」一致)。
150 154
 
151
-**列表宜展示:** 草场名称、面积(亩)、退化等级、利用类型、亩产草量(kg/亩)、利用率、禁牧开始日期、禁牧结束日期、轮牧小区数量(块)、小区放牧天数(天)、轮牧周期(天)、操作列(查看 / 编辑 / 删除);**地图标点**入口本期不展示或置灰并提示「暂未开放」。
155
+**列表宜展示:** 草场名称、面积(亩)、禁牧面积(亩)、草畜平衡面积(亩)、退化等级、利用类型、亩产草量(kg/亩)、利用率、禁牧开始日期、禁牧结束日期、轮牧小区数量(块)、小区放牧天数(天)、轮牧周期(天)、操作列(查看 / 编辑 / 删除);**地图标点**入口本期不展示或置灰并提示「暂未开放」。
152 156
 
153 157
 ---
154 158
 
155 159
 ### 5.3 修改草场
156 160
 
157
-- **可修改项:** 草场名称、面积、退化等级、利用类型、亩产草量、利用率、禁牧开始日期、禁牧结束日期、轮牧小区数量、小区放牧天数、轮牧周期、备注(**全部业务字段**均可修改)。  
158
-- **保存约束:** 须重新满足 **§5.1** 全部校验;必填项不得为空。  
159
-- **利用类型变更:** 允许在禁牧 / 轮牧 / 全年放牧之间变更;变更后仍须满足全部字段校验;宜提示用户核对与新区划方式不一致的历史指标(提示文案由产品确定,非阻断性)。  
160
-- **日期变更:** 修改禁牧开始或结束日期后,仍须满足「开始日 ≤ 结束日」。  
161
+- **可修改项:** 草场名称、面积、禁牧面积、草畜平衡面积、退化等级、利用类型、亩产草量、利用率、禁牧开始日期、禁牧结束日期、轮牧小区数量、小区放牧天数、轮牧周期、备注(**全部业务字段**均可修改)。  
162
+- **保存约束:** 须重新满足 **§5.1** 全部校验;必填项(草场名称、面积)不得为空。  
163
+- **利用类型变更:** 允许在禁牧 / 轮牧 / 全年放牧之间变更;变更后仍须满足已填字段校验;宜提示用户核对与新区划方式不一致的历史指标(提示文案由产品确定,非阻断性)。  
164
+- **日期变更:** 修改禁牧开始或结束日期后,仍须满足「同时有值或同时为空」且「开始日 ≤ 结束日」。  
161 165
 
162 166
 ---
163 167
 
@@ -175,7 +179,7 @@ flowchart LR
175 179
 
176 180
 ### 5.5 查看草场详情
177 181
 
178
-- **展示内容:** 草场名称、面积、退化等级、利用类型、亩产草量、利用率、禁牧开始日期、禁牧结束日期、轮牧小区数量、小区放牧天数、轮牧周期、备注;宜展示创建人、创建时间、最后修改人、最后修改时间(若系统有审计字段)。  
182
+- **展示内容:** 草场名称、面积、禁牧面积、草畜平衡面积、退化等级、利用类型、亩产草量、利用率、禁牧开始日期、禁牧结束日期、轮牧小区数量、小区放牧天数、轮牧周期、备注;宜展示创建人、创建时间、最后修改人、最后修改时间(若系统有审计字段)。  
179 183
 - **展示格式:** 日期按 **YYYY-MM-DD** 展示;数值带单位说明(亩、kg/亩、块、天等)与列表或表单一致。  
180 184
 - **交互:** 具备编辑权限的用户可从详情进入编辑(见 **§5.3**);只读账号仅可查看。
181 185
 

+ 34 - 58
doc/产业数据模型及服务/草场管理/草场管理技术方案.md

@@ -36,52 +36,24 @@
36 36
 | `id` | `bigint(20)` | Y | 自增 | 主键 |
37 37
 | `grassland_name` | `varchar(32)` | Y | — | 草场名称(需求 **1~10** 字) |
38 38
 | `area_mu` | `decimal(12,2)` | Y | — | 面积(**亩**),> 0 |
39
-| `degradation_level` | `tinyint(4)` | Y | — | 退化等级 **§2.2** |
40
-| `utilization_type` | `tinyint(4)` | Y | — | 利用类型 **§2.2** |
41
-| `grass_yield_per_mu` | `decimal(12,2)` | Y | — | 亩产草量(**kg/亩**),> 0 |
42
-| `utilization_rate` | `decimal(5,4)` | Y | — | 利用率 **0~1**(闭区间) |
43
-| `grazing_ban_start_date` | `date` | Y | — | 禁牧开始日期 |
44
-| `grazing_ban_end_date` | `date` | Y | — | 禁牧结束日期;≥ 开始日 |
45
-| `rotation_plot_count` | `int(11)` | Y | — | 轮牧小区数量(**块**),≥ 1 |
46
-| `rotation_grazing_days` | `int(11)` | Y | — | 小区放牧天数(**天**),≥ 1 |
47
-| `rotation_cycle_days` | `int(11)` | Y | — | 轮牧周期(**天**),≥ 1 |
39
+| `grazing_ban_area` | `decimal(12,2)` | N | NULL | 禁牧面积(**亩**),有值须 > 0 |
40
+| `grass_balance_area` | `decimal(12,2)` | N | NULL | 草畜平衡面积(**亩**),有值须 > 0 |
41
+| `degradation_level` | `tinyint(4)` | N | NULL | 退化等级 **§2.2** |
42
+| `utilization_type` | `tinyint(4)` | N | NULL | 利用类型 **§2.2** |
43
+| `grass_yield_per_mu` | `decimal(12,2)` | N | NULL | 亩产草量(**kg/亩**),有值须 > 0 |
44
+| `utilization_rate` | `decimal(5,4)` | N | NULL | 利用率 **0~1**(闭区间) |
45
+| `grazing_ban_start_date` | `date` | N | NULL | 禁牧开始日期(与结束成对) |
46
+| `grazing_ban_end_date` | `date` | N | NULL | 禁牧结束日期;有值时 ≥ 开始日 |
47
+| `rotation_plot_count` | `int(11)` | N | NULL | 轮牧小区数量(**块**),有值须 ≥ 1 |
48
+| `rotation_grazing_days` | `int(11)` | N | NULL | 小区放牧天数(**天**),有值须 ≥ 1 |
49
+| `rotation_cycle_days` | `int(11)` | N | NULL | 轮牧周期(**天**),有值须 ≥ 1 |
48 50
 | `del_flag` | `char(1)` | Y | `'0'` | `0` 存在 `2` 删除 |
49 51
 | `create_by` / `create_time` / `update_by` / `update_time` | 若依惯例 | — | — | 审计 |
50 52
 | `remark` | `varchar(200)` | N | NULL | 备注(≤100 字) |
51 53
 
52 54
 **索引**:`PRIMARY KEY (id)`;`KEY idx_grassland_name (grassland_name)`;`KEY idx_utilization_type (utilization_type)`;`KEY idx_degradation_level (degradation_level)`;`KEY idx_create_time (create_time)`;`KEY idx_del_flag (del_flag)`。
53 55
 
54
-**DDL(MySQL 5.7)**
55
-
56
-```sql
57
-CREATE TABLE `biz_grassland` (
58
-  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
59
-  `grassland_name` varchar(32) NOT NULL COMMENT '草场名称',
60
-  `area_mu` decimal(12,2) NOT NULL COMMENT '面积(亩)',
61
-  `degradation_level` tinyint(4) NOT NULL COMMENT '退化等级1-5',
62
-  `utilization_type` tinyint(4) NOT NULL COMMENT '利用类型1禁牧2轮牧3全年放牧',
63
-  `grass_yield_per_mu` decimal(12,2) NOT NULL COMMENT '亩产草量kg/亩',
64
-  `utilization_rate` decimal(5,4) NOT NULL COMMENT '利用率0-1',
65
-  `grazing_ban_start_date` date NOT NULL COMMENT '禁牧开始日期',
66
-  `grazing_ban_end_date` date NOT NULL COMMENT '禁牧结束日期',
67
-  `rotation_plot_count` int(11) NOT NULL COMMENT '轮牧小区数量(块)',
68
-  `rotation_grazing_days` int(11) NOT NULL COMMENT '小区放牧天数(天)',
69
-  `rotation_cycle_days` int(11) NOT NULL COMMENT '轮牧周期(天)',
70
-  `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0存在 2删除',
71
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
72
-  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
73
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
74
-  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
75
-  `remark` varchar(200) DEFAULT NULL COMMENT '备注',
76
-  PRIMARY KEY (`id`),
77
-  KEY `idx_grassland_name` (`grassland_name`),
78
-  KEY `idx_utilization_type` (`utilization_type`),
79
-  KEY `idx_degradation_level` (`degradation_level`),
80
-  KEY `idx_create_time` (`create_time`),
81
-  KEY `idx_del_flag` (`del_flag`)
82
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='草场管理';
83
-```
84
-
56
+**DDL(MySQL 5.7)**:见 `sql/biz_grassland.sql`;已有库升级见 `sql/biz_grassland_fields_alter.sql`。
85 57
 ### 2.2 枚举常量
86 58
 
87 59
 | 字段 | 值 | 含义 |
@@ -131,18 +103,20 @@ CREATE TABLE `biz_grassland` (
131 103
 | `id` | 修改 Y | 主键 |
132 104
 | `grasslandName` | Y | 1~10 字符 |
133 105
 | `areaMu` | Y | 正数(亩) |
134
-| `degradationLevel` | Y | `1`~`5` |
135
-| `utilizationType` | Y | `1`~`3` |
136
-| `grassYieldPerMu` | Y | 正数(kg/亩) |
137
-| `utilizationRate` | Y | `0`~`1`(含端点) |
138
-| `grazingBanStartDate` | Y | `yyyy-MM-dd` |
139
-| `grazingBanEndDate` | Y | `yyyy-MM-dd`;≥ `grazingBanStartDate` |
140
-| `rotationPlotCount` | Y | 正整数(块) |
141
-| `rotationGrazingDays` | Y | 正整数(天) |
142
-| `rotationCycleDays` | Y | 正整数(天) |
106
+| `grazingBanArea` | N | 正数(亩);空不校验 |
107
+| `grassBalanceArea` | N | 正数(亩);空不校验 |
108
+| `degradationLevel` | N | `1`~`5`;空不校验 |
109
+| `utilizationType` | N | `1`~`3`;空不校验 |
110
+| `grassYieldPerMu` | N | 正数(kg/亩);空不校验 |
111
+| `utilizationRate` | N | `0`~`1`(含端点);空不校验 |
112
+| `grazingBanStartDate` | N | `yyyy-MM-dd`;与结束成对 |
113
+| `grazingBanEndDate` | N | `yyyy-MM-dd`;有值时 ≥ `grazingBanStartDate` |
114
+| `rotationPlotCount` | N | 正整数(块);空不校验 |
115
+| `rotationGrazingDays` | N | 正整数(天);空不校验 |
116
+| `rotationCycleDays` | N | 正整数(天);空不校验 |
143 117
 | `remark` | N | ≤100 字 |
144 118
 
145
-**列表行字段(示例)**:`id`、`grasslandName`、`areaMu`、`degradationLevel`、`utilizationType`、`grassYieldPerMu`、`utilizationRate`、`grazingBanStartDate`、`grazingBanEndDate`、`rotationPlotCount`、`rotationGrazingDays`、`rotationCycleDays`、`createTime`。
119
+**列表行字段(示例)**:`id`、`grasslandName`、`areaMu`、`grazingBanArea`、`grassBalanceArea`、`degradationLevel`、`utilizationType`、`grassYieldPerMu`、`utilizationRate`、`grazingBanStartDate`、`grazingBanEndDate`、`rotationPlotCount`、`rotationGrazingDays`、`rotationCycleDays`、`createTime`。
146 120
 
147 121
 **日期序列化**:JSON 使用 `yyyy-MM-dd`;与若依 `JsonFormat` / 全局 Jackson 配置一致。
148 122
 
@@ -156,14 +130,15 @@ CREATE TABLE `biz_grassland` (
156 130
 
157 131
 | 项 | 规则 |
158 132
 | --- | --- |
159
-| 草场名称 | 非空,1~10 字符 |
160
-| 面积 | > 0;`decimal` 合法 |
161
-| 退化等级 | ∈ {1, 2, 3, 4, 5} |
162
-| 利用类型 | ∈ {1, 2, 3} |
163
-| 亩产草量 | > 0 |
164
-| 利用率 | 0 ≤ x ≤ 1 |
165
-| 禁牧日期 | 起止非空;`start ≤ end` |
166
-| 轮牧三项 | 均为 ≥ 1 的整数 |
133
+| 草场名称 | **必填**;1~10 字符 |
134
+| 面积 | **必填**;> 0 |
135
+| 禁牧面积 / 草畜平衡面积 | 选填;有值须 > 0 |
136
+| 退化等级 | 选填;有值 ∈ {1, 2, 3, 4, 5} |
137
+| 利用类型 | 选填;有值 ∈ {1, 2, 3} |
138
+| 亩产草量 | 选填;有值须 > 0 |
139
+| 利用率 | 选填;有值 0 ≤ x ≤ 1 |
140
+| 禁牧日期 | 选填;同时有值或同时为空;有值时 `start ≤ end` |
141
+| 轮牧三项 | 选填;有值均为 ≥ 1 的整数 |
167 142
 | 备注 | 可空;有值 ≤100 字 |
168 143
 
169 144
 校验类建议:`GrasslandRules`(枚举常量)、`GrasslandValidation`(`validateRowForSave`)。
@@ -200,3 +175,4 @@ CREATE TABLE `biz_grassland` (
200 175
 | 版本 | 说明 |
201 176
 | --- | --- |
202 177
 | 1.0 | 初稿:对齐功能需求;`biz_grassland`;逻辑删除 `del_flag`;无地图与附件接口 |
178
+| 1.1 | 新增禁牧面积、草畜平衡面积;除名称与面积外字段改为可空/选填 |

+ 8 - 8
doc/产业数据模型及服务/草场管理/草场管理测试用例.md

@@ -15,13 +15,13 @@
15 15
 | --- | --- | --- | --- | --- | --- | --- | --- | --- |
16 16
 | ZCZX-CCGL-UT-001 | 参数校验 | 草场名称长度 | 单元测试 | JUnit5 | 1~10 字 | 无 | 空串、1 字、10 字、11 字 | 空/11 失败;1~10 通过 |
17 17
 | ZCZX-CCGL-UT-002 | 参数校验 | 备注字数 | 单元测试 | JUnit5 | 选填≤100 | 无 | null/空通过;101 字失败 | 符合功能需求 §5.1 |
18
-| ZCZX-CCGL-UT-003 | 参数校验 | 退化等级枚举 | 单元测试 | JUnit5 | 仅 1~5 | 无 | 值为 1/5 通过;0、6、null 失败 | 与技术方案 §2.2 一致 |
19
-| ZCZX-CCGL-UT-004 | 参数校验 | 利用类型枚举 | 单元测试 | JUnit5 | 仅 1~3 | 无 | 值为 1/3 通过;0、4、null 失败 | 与技术方案 §2.2 一致 |
20
-| ZCZX-CCGL-UT-005 | 参数校验 | 面积/亩产草量 | 单元测试 | JUnit5 | 正数 | 无 | 面积 0、负数;亩产草量 0 | 均失败;合法正数通过 |
21
-| ZCZX-CCGL-UT-006 | 参数校验 | 利用率区间 | 单元测试 | JUnit5 | 0~1 闭区间 | 无 | `-0.1`、`1.1`、`0`、`1` | 越界失败;0 与 1 通过 |
22
-| ZCZX-CCGL-UT-007 | 参数校验 | 禁牧日期区间 | 单元测试 | JUnit5 | 起止成对 | 无 | 开始晚于结束;仅一端;合法区间 | 颠倒/缺一端失败;`start≤end` 通过 |
23
-| ZCZX-CCGL-UT-008 | 参数校验 | 轮牧三项整数 | 单元测试 | JUnit5 | ≥1 整数 | 无 | 小区数/放牧天数/周期为 0、小数、负数 | 失败;正整数通过 |
24
-| ZCZX-CCGL-UT-009 | 参数校验 | 全量保存校验 | 单元测试 | JUnit5 | `validateRowForSave` | 合法 `BizGrassland` | 调用校验后写库字段 | 各字段 trim/枚举/数值符合 §3.5 |
18
+| ZCZX-CCGL-UT-003 | 参数校验 | 退化等级枚举 | 单元测试 | JUnit5 | 选填;有值仅 1~5 | 无 | null 通过;值为 1/5 通过;0、6 失败 | 与技术方案 §2.2 一致 |
19
+| ZCZX-CCGL-UT-004 | 参数校验 | 利用类型枚举 | 单元测试 | JUnit5 | 选填;有值仅 1~3 | 无 | null 通过;值为 1/3 通过;0、4 失败 | 与技术方案 §2.2 一致 |
20
+| ZCZX-CCGL-UT-005 | 参数校验 | 面积/亩产/禁牧与草畜平衡面积 | 单元测试 | JUnit5 | 正数 | 无 | 面积 0、负数;亩产/禁牧/草畜平衡面积 0 | 面积必填失败;选填有值非法失败;合法正数通过 |
21
+| ZCZX-CCGL-UT-006 | 参数校验 | 利用率区间 | 单元测试 | JUnit5 | 选填 0~1 | 无 | null 通过;`-0.1`、`1.1` 失败;`0`、`1` 通过 | 越界失败 |
22
+| ZCZX-CCGL-UT-007 | 参数校验 | 禁牧日期区间 | 单元测试 | JUnit5 | 选填成对 | 无 | 双空通过;开始晚于结束;仅一端;合法区间 | 颠倒/缺一端失败;`start≤end` 通过 |
23
+| ZCZX-CCGL-UT-008 | 参数校验 | 轮牧三项整数 | 单元测试 | JUnit5 | 选填 ≥1 | 无 | null 通过;小区数/放牧天数/周期为 0 | 失败;正整数通过 |
24
+| ZCZX-CCGL-UT-009 | 参数校验 | 全量保存校验 | 单元测试 | JUnit5 | `validateRowForSave` | 合法 `BizGrassland` | 仅名称+面积;全字段;利用率非法 | 最小必填通过;非法失败 |
25 25
 | ZCZX-CCGL-UT-010 | Service | 新增落库 | 单元测试 | JUnit5+Mockito | 正常登记 | 合法实体 | `insert(grassland)` | `del_flag='0'`;数值与入参一致 |
26 26
 | ZCZX-CCGL-UT-011 | Service | 修改全字段 | 单元测试 | JUnit5+Mockito | §5.3 | Mock 已存在 id | `update` 改名称、面积、退化等级、日期、轮牧参数 | 更新成功;Mapper `update` 被调用 |
27 27
 | ZCZX-CCGL-UT-012 | Service | 利用类型互改 | 单元测试 | JUnit5+Mockito | 1↔2↔3 | 原 `utilization_type=1` | `update` 改为 `2` 或 `3` 且指标仍合法 | 成功(本期不因类型豁免字段) |
@@ -44,7 +44,7 @@
44 44
 | ZCZX-CCGL-API-006 | 列表 | 不含已删除 | 接口测试 | Postman | 逻辑删除 | 已知 id 已删 | `GET list` | 列表无该 id |
45 45
 | ZCZX-CCGL-API-007 | 列表 | 分页参数 | 接口测试 | Postman | 分页 | 已登录 | `pageNum=2&pageSize=10` | 返回第 2 页;条数≤10 |
46 46
 | ZCZX-CCGL-API-008 | 新增 | 合法全字段 | 接口测试 | Postman | §5.1 | 已登录 | `POST` Body 含备注等全部合法字段 | `code` 成功;`GET` 详情字段一致 |
47
-| ZCZX-CCGL-API-009 | 新增 | 最小必填无备注 | 接口测试 | Postman | 备注选填 | 已登录 | `POST` 不传 `remark` | 成功;详情备注为空 |
47
+| ZCZX-CCGL-API-009 | 新增 | 最小必填(仅名称+面积) | 接口测试 | Postman | 其余选填 | 已登录 | `POST` 仅 `grasslandName`+`areaMu` | 成功;其余字段为空 |
48 48
 | ZCZX-CCGL-API-010 | 新增 | 利用类型-禁牧 | 接口测试 | Postman | §2.2 | 已登录 | `utilizationType=1`+合法指标 | 成功 |
49 49
 | ZCZX-CCGL-API-011 | 新增 | 利用类型-轮牧 | 接口测试 | Postman | §2.2 | 已登录 | `utilizationType=2`+合法轮牧参数 | 成功 |
50 50
 | ZCZX-CCGL-API-012 | 新增 | 利用类型-全年放牧 | 接口测试 | Postman | §2.2 | 已登录 | `utilizationType=3` | 成功 |

+ 11 - 9
sql/biz_grassland.sql

@@ -3,15 +3,17 @@ CREATE TABLE IF NOT EXISTS `biz_grassland` (
3 3
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
4 4
   `grassland_name` varchar(32) NOT NULL COMMENT '草场名称',
5 5
   `area_mu` decimal(12,2) NOT NULL COMMENT '面积(亩)',
6
-  `degradation_level` tinyint(4) NOT NULL COMMENT '退化等级1-5',
7
-  `utilization_type` tinyint(4) NOT NULL COMMENT '利用类型1禁牧2轮牧3全年放牧',
8
-  `grass_yield_per_mu` decimal(12,2) NOT NULL COMMENT '亩产草量kg/亩',
9
-  `utilization_rate` decimal(5,4) NOT NULL COMMENT '利用率0-1',
10
-  `grazing_ban_start_date` date NOT NULL COMMENT '禁牧开始日期',
11
-  `grazing_ban_end_date` date NOT NULL COMMENT '禁牧结束日期',
12
-  `rotation_plot_count` int(11) NOT NULL COMMENT '轮牧小区数量(块)',
13
-  `rotation_grazing_days` int(11) NOT NULL COMMENT '小区放牧天数(天)',
14
-  `rotation_cycle_days` int(11) NOT NULL COMMENT '轮牧周期(天)',
6
+  `grazing_ban_area` decimal(12,2) DEFAULT NULL COMMENT '禁牧面积(亩)',
7
+  `grass_balance_area` decimal(12,2) DEFAULT NULL COMMENT '草畜平衡面积(亩)',
8
+  `degradation_level` tinyint(4) DEFAULT NULL COMMENT '退化等级1-5',
9
+  `utilization_type` tinyint(4) DEFAULT NULL COMMENT '利用类型1禁牧2轮牧3全年放牧',
10
+  `grass_yield_per_mu` decimal(12,2) DEFAULT NULL COMMENT '亩产草量kg/亩',
11
+  `utilization_rate` decimal(5,4) DEFAULT NULL COMMENT '利用率0-1',
12
+  `grazing_ban_start_date` date DEFAULT NULL COMMENT '禁牧开始日期',
13
+  `grazing_ban_end_date` date DEFAULT NULL COMMENT '禁牧结束日期',
14
+  `rotation_plot_count` int(11) DEFAULT NULL COMMENT '轮牧小区数量(块)',
15
+  `rotation_grazing_days` int(11) DEFAULT NULL COMMENT '小区放牧天数(天)',
16
+  `rotation_cycle_days` int(11) DEFAULT NULL COMMENT '轮牧周期(天)',
15 17
   `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0存在 2删除',
16 18
   `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
17 19
   `create_time` datetime DEFAULT NULL COMMENT '创建时间',