Parcourir la Source

畜牧产品产量登记

wwh il y a 2 semaines
Parent
commit
43a82f10f9

+ 108 - 3
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/service/impl/BizFarmerHouseholdServiceImpl.java

@@ -1,6 +1,7 @@
1 1
 package com.ruoyi.web.modules.industryservice.service.impl;
2 2
 
3 3
 import java.util.ArrayList;
4
+import java.util.Date;
4 5
 import java.util.List;
5 6
 import org.springframework.beans.factory.annotation.Autowired;
6 7
 import org.springframework.stereotype.Service;
@@ -10,14 +11,18 @@ import com.ruoyi.common.core.domain.entity.SysDept;
10 11
 import com.ruoyi.common.exception.ServiceException;
11 12
 import com.ruoyi.common.utils.StringUtils;
12 13
 import com.ruoyi.web.modules.industryservice.domain.BizFarmerHousehold;
14
+import com.ruoyi.web.modules.industryservice.domain.BizYakDiseaseWarning;
13 15
 import com.ruoyi.web.modules.industryservice.domain.vo.FarmerHouseholdImportResultVo;
14 16
 import com.ruoyi.web.modules.industryservice.mapper.BizFarmerHouseholdMapper;
17
+import com.ruoyi.web.modules.industryservice.mapper.BizYakDiseaseWarningMapper;
15 18
 import com.ruoyi.web.modules.industryservice.service.IBizFarmerHouseholdService;
19
+import com.ruoyi.web.modules.industryservice.support.FarmerHouseholdDerivedSupport;
16 20
 import com.ruoyi.web.modules.industryservice.support.FarmerHouseholdExcelExporter;
17 21
 import com.ruoyi.web.modules.industryservice.support.FarmerHouseholdExcelParser;
18 22
 import com.ruoyi.web.modules.industryservice.support.FarmerHouseholdExcelParser.ParsedRow;
19 23
 import com.ruoyi.web.modules.industryservice.support.FarmerHouseholdValidation;
20 24
 import com.ruoyi.web.modules.industryservice.support.TownDeptSupport;
25
+import com.ruoyi.web.modules.industryservice.support.YakDiseaseWarningRules;
21 26
 import com.ruoyi.web.modules.industryservice.support.YakHerdInventoryMonthSupport;
22 27
 import com.ruoyi.web.modules.industryservice.support.YakHerdInventoryYearSupport;
23 28
 
@@ -30,6 +35,9 @@ public class BizFarmerHouseholdServiceImpl implements IBizFarmerHouseholdService
30 35
     @Autowired
31 36
     private BizFarmerHouseholdMapper bizFarmerHouseholdMapper;
32 37
 
38
+    @Autowired
39
+    private BizYakDiseaseWarningMapper bizYakDiseaseWarningMapper;
40
+
33 41
     @Autowired
34 42
     private TownDeptSupport townDeptSupport;
35 43
 
@@ -54,7 +62,9 @@ public class BizFarmerHouseholdServiceImpl implements IBizFarmerHouseholdService
54 62
     {
55 63
         FarmerHouseholdValidation.validateRowForSave(row, townDeptSupport);
56 64
         assertUniqueYearMonthVillage(row.getStatYear(), row.getStatMonth(), row.getVillageDeptId(), null);
57
-        return bizFarmerHouseholdMapper.insertBizFarmerHousehold(row);
65
+        int rows = bizFarmerHouseholdMapper.insertBizFarmerHousehold(row);
66
+        syncGrassImbalanceWarning(row);
67
+        return rows;
58 68
     }
59 69
 
60 70
     @Override
@@ -68,7 +78,9 @@ public class BizFarmerHouseholdServiceImpl implements IBizFarmerHouseholdService
68 78
         FarmerHouseholdValidation.validateRowForSave(row, townDeptSupport);
69 79
         requireExistingRow(row.getId());
70 80
         assertUniqueYearMonthVillage(row.getStatYear(), row.getStatMonth(), row.getVillageDeptId(), row.getId());
71
-        return bizFarmerHouseholdMapper.updateBizFarmerHousehold(row);
81
+        int rows = bizFarmerHouseholdMapper.updateBizFarmerHousehold(row);
82
+        syncGrassImbalanceWarning(row);
83
+        return rows;
72 84
     }
73 85
 
74 86
     @Override
@@ -91,7 +103,15 @@ public class BizFarmerHouseholdServiceImpl implements IBizFarmerHouseholdService
91 103
         {
92 104
             return 0;
93 105
         }
94
-        return bizFarmerHouseholdMapper.deleteBizFarmerHouseholdByIds(cleaned.toArray(new Long[0]));
106
+        Long[] householdIds = cleaned.toArray(new Long[0]);
107
+        List<String> deviceNos = new ArrayList<>();
108
+        for (Long householdId : householdIds)
109
+        {
110
+            deviceNos.add(YakDiseaseWarningRules.farmerHouseholdDeviceNo(householdId));
111
+        }
112
+        bizYakDiseaseWarningMapper.deleteByDataSourceAndDeviceNos(
113
+                YakDiseaseWarningRules.DATA_SOURCE_FARMER_HOUSEHOLD, deviceNos);
114
+        return bizFarmerHouseholdMapper.deleteBizFarmerHouseholdByIds(householdIds);
95 115
     }
96 116
 
97 117
     /**
@@ -195,6 +215,7 @@ public class BizFarmerHouseholdServiceImpl implements IBizFarmerHouseholdService
195 215
                 bizFarmerHouseholdMapper.insertBizFarmerHousehold(row);
196 216
                 result.setInsertCount(result.getInsertCount() + 1);
197 217
             }
218
+            syncGrassImbalanceWarning(row);
198 219
         }
199 220
         return result;
200 221
     }
@@ -245,6 +266,90 @@ public class BizFarmerHouseholdServiceImpl implements IBizFarmerHouseholdService
245 266
         return farmerHouseholdExcelExporter.export(statYear, statMonth, list, fillerName);
246 267
     }
247 268
 
269
+    /**
270
+     * 草畜失衡时写入 biz_yak_disease_warning;恢复平衡则删除对应预警。
271
+     * 定位键:data_source=farmer_household + device_no=FH-{id}
272
+     */
273
+    private void syncGrassImbalanceWarning(BizFarmerHousehold row)
274
+    {
275
+        if (row == null || row.getId() == null)
276
+        {
277
+            return;
278
+        }
279
+        String deviceNo = YakDiseaseWarningRules.farmerHouseholdDeviceNo(row.getId());
280
+        if (FarmerHouseholdDerivedSupport.isImbalanced(row))
281
+        {
282
+            Date now = new Date();
283
+            BizYakDiseaseWarning existing = bizYakDiseaseWarningMapper.selectByDataSourceAndDeviceNo(
284
+                    YakDiseaseWarningRules.DATA_SOURCE_FARMER_HOUSEHOLD, deviceNo);
285
+            BizYakDiseaseWarning warning = new BizYakDiseaseWarning();
286
+            warning.setDeviceNo(deviceNo);
287
+            warning.setDataSource(YakDiseaseWarningRules.DATA_SOURCE_FARMER_HOUSEHOLD);
288
+            warning.setWarningType(YakDiseaseWarningRules.WARNING_TYPE_GRASS_IMBALANCE);
289
+            warning.setPastureId(null);
290
+            warning.setPastureName(row.getVillageName());
291
+            warning.setYakNo(null);
292
+            warning.setAlertTime(now);
293
+            warning.setCollectTime(now);
294
+            warning.setLastSyncTime(now);
295
+            warning.setUpdateTime(now);
296
+            warning.setMeasuredValue(row.getYearEndStockSheepUnit() == null ? null
297
+                    : row.getYearEndStockSheepUnit().stripTrailingZeros().toPlainString());
298
+            warning.setReferenceRange(row.getApprovedCarryingCapacity() == null ? null
299
+                    : row.getApprovedCarryingCapacity().stripTrailingZeros().toPlainString());
300
+            warning.setAlertMessage(buildGrassImbalanceMessage(row));
301
+            if (existing == null)
302
+            {
303
+                warning.setCreateTime(now);
304
+                bizYakDiseaseWarningMapper.insertBizYakDiseaseWarning(warning);
305
+            }
306
+            else
307
+            {
308
+                warning.setId(existing.getId());
309
+                bizYakDiseaseWarningMapper.updateAlertContent(warning);
310
+            }
311
+        }
312
+        else
313
+        {
314
+            bizYakDiseaseWarningMapper.deleteByDataSourceAndDeviceNo(
315
+                    YakDiseaseWarningRules.DATA_SOURCE_FARMER_HOUSEHOLD, deviceNo);
316
+        }
317
+    }
318
+
319
+    private static String buildGrassImbalanceMessage(BizFarmerHousehold row)
320
+    {
321
+        StringBuilder sb = new StringBuilder();
322
+        sb.append("草畜失衡预警:");
323
+        if (row.getStatYear() != null)
324
+        {
325
+            sb.append(row.getStatYear()).append("年");
326
+        }
327
+        if (row.getStatMonth() != null)
328
+        {
329
+            sb.append(row.getStatMonth()).append("月");
330
+        }
331
+        if (StringUtils.isNotEmpty(row.getTownName()) || StringUtils.isNotEmpty(row.getVillageName()))
332
+        {
333
+            sb.append(" ");
334
+            if (StringUtils.isNotEmpty(row.getTownName()))
335
+            {
336
+                sb.append(row.getTownName());
337
+            }
338
+            if (StringUtils.isNotEmpty(row.getVillageName()))
339
+            {
340
+                sb.append(row.getVillageName());
341
+            }
342
+        }
343
+        sb.append(":核定年末草畜平衡载畜量(")
344
+                .append(row.getApprovedCarryingCapacity() == null ? "-"
345
+                        : row.getApprovedCarryingCapacity().stripTrailingZeros().toPlainString())
346
+                .append(")小于年底牲畜存栏绵羊单位(")
347
+                .append(row.getYearEndStockSheepUnit() == null ? "-"
348
+                        : row.getYearEndStockSheepUnit().stripTrailingZeros().toPlainString())
349
+                .append(")");
350
+        return sb.toString();
351
+    }
352
+
248 353
     private void assertUniqueYearMonthVillage(Integer statYear, Integer statMonth, Long villageDeptId, Long excludeId)
249 354
     {
250 355
         if (bizFarmerHouseholdMapper.countByYearMonthAndVillageExcludeId(statYear, statMonth, villageDeptId,

+ 10 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/support/FarmerHouseholdDerivedSupport.java

@@ -29,6 +29,16 @@ public final class FarmerHouseholdDerivedSupport
29 29
         row.setSubsidyTotal(safeDec(row.getAfterCapFloorSubsidy()).add(safeDec(row.getVillageSupervisorSubsidy())));
30 30
     }
31 31
 
32
+    /** 核定载畜量 &lt; 年底存栏绵羊单位 → 草畜失衡 */
33
+    public static boolean isImbalanced(BizFarmerHousehold row)
34
+    {
35
+        if (row == null || row.getApprovedCarryingCapacity() == null || row.getYearEndStockSheepUnit() == null)
36
+        {
37
+            return false;
38
+        }
39
+        return row.getApprovedCarryingCapacity().compareTo(row.getYearEndStockSheepUnit()) < 0;
40
+    }
41
+
32 42
     public static String normalizeYesNo(String value, String fieldLabel)
33 43
     {
34 44
         if (StringUtils.isEmpty(value))

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

@@ -15,7 +15,7 @@ public final class YakDiseaseWarningRules
15 15
 
16 16
     public static final int WARNING_TYPE_AI_CONSULT = 5;
17 17
 
18
-    /** 家庭牧场草畜失衡 */
18
+    /** 草畜失衡(家庭牧场 / 农牧户填报触发) */
19 19
     public static final int WARNING_TYPE_GRASS_IMBALANCE = 6;
20 20
 
21 21
     public static final int WARNING_TYPE_OTHER = 9;
@@ -25,9 +25,15 @@ public final class YakDiseaseWarningRules
25 25
     /** 家庭牧场填报触发的草畜失衡预警 */
26 26
     public static final String DATA_SOURCE_FAMILY_RANCH = "family_ranch";
27 27
 
28
-    /** device_no 前缀,用于按牧场记录定位预警 */
28
+    /** 农牧户填报触发的草畜失衡预警 */
29
+    public static final String DATA_SOURCE_FARMER_HOUSEHOLD = "farmer_household";
30
+
31
+    /** device_no 前缀,用于按家庭牧场记录定位预警 */
29 32
     public static final String FAMILY_RANCH_DEVICE_PREFIX = "FR-";
30 33
 
34
+    /** device_no 前缀,用于按农牧户填报记录定位预警 */
35
+    public static final String FARMER_HOUSEHOLD_DEVICE_PREFIX = "FH-";
36
+
31 37
     public static final String MSG_DATE_RANGE_INVALID = "开始日期不能晚于结束日期";
32 38
 
33 39
     public static final String MSG_NOT_FOUND = "预警记录不存在";
@@ -45,6 +51,11 @@ public final class YakDiseaseWarningRules
45 51
         return FAMILY_RANCH_DEVICE_PREFIX + ranchId;
46 52
     }
47 53
 
54
+    public static String farmerHouseholdDeviceNo(Long householdId)
55
+    {
56
+        return FARMER_HOUSEHOLD_DEVICE_PREFIX + householdId;
57
+    }
58
+
48 59
     public static boolean isValidWarningType(Integer type)
49 60
     {
50 61
         return type != null && (type == WARNING_TYPE_TEMP || type == WARNING_TYPE_STEPS

+ 3 - 1
doc/产业数据模型及服务/农牧户数据填报/农牧户数据填报功能需求.md

@@ -22,6 +22,7 @@
22 22
   - 补助奖励总资金 = 禁牧补助 + 草畜平衡奖励
23 23
   - 补助合计金额 = 封顶保底后享受补助奖励总资金 + 村级草原监督员补助
24 24
 - 封顶保底六项(是否是纯牧户等)按模板填写「是 / 否」。
25
+- 草畜失衡预警:核定年末草畜平衡载畜量 &lt; 年底牲畜存栏(绵羊单位)时写入 **`biz_yak_disease_warning`**(`warning_type=6`,`data_source=farmer_household`,`device_no=FH-{id}`);恢复平衡或删除记录时清除对应预警。不另建预警表。
25 26
 
26 27
 ---
27 28
 
@@ -32,7 +33,7 @@
32 33
 | 分页列表 | 筛选:年、月、乡镇;列:年、月、乡镇、村、户数、人数、草场承包总面积 |
33 34
 | 新增 / 修改 | 选村(级联);新增默认本年本月;不展示派生小计(保存后详情可见) |
34 35
 | 详情 | 全部字段含派生 |
35
-| 删除 | 物理删除 |
36
+| 删除 | 物理删除(级联清预警) |
36 37
 | Excel 导入 | 多级表头;另选年月;按唯一键 upsert;任一行失败整批不写 |
37 38
 | Excel 导出 | 另选年月;**所属乡镇与列表一致**(打开时带入列表当前乡镇,可清空表示全部);填表人=登录用户 |
38 39
 
@@ -49,3 +50,4 @@
49 50
 | 版本 | 说明 |
50 51
 | --- | --- |
51 52
 | 1.0 | 首版:CRUD + upsert 导入 + 导出;派生三项;村级唯一键 |
53
+| 1.1 | 补草畜失衡预警:写入疾病预警表 type=6 |

+ 6 - 0
doc/产业数据模型及服务/农牧户数据填报/农牧户数据填报技术方案.md

@@ -23,6 +23,12 @@ Base Path:`/dataModel/farmerHousehold`
23 23
 - 主表 `biz_farmer_household`
24 24
 - 唯一键 `(stat_year, stat_month, village_dept_id)`
25 25
 - 派生落库:`pasture_contract_area`、`subsidy_reward_subtotal`、`subsidy_total`
26
+- 草畜失衡预警:**复用** `biz_yak_disease_warning`
27
+  - `warning_type = 6`(草畜失衡)
28
+  - `data_source = farmer_household`
29
+  - `device_no = FH-{id}`(定位/去重)
30
+  - `pasture_name` = 村名;`measured_value` = 存栏绵羊单位;`reference_range` = 核定载畜量
31
+  - 失衡 upsert;平衡或删除填报记录时按 `data_source + device_no` 删除
26 32
 
27 33
 ## 3. Excel
28 34
 

+ 1 - 0
doc/产业数据模型及服务/农牧户数据填报/农牧户数据填报测试用例.md

@@ -15,6 +15,7 @@
15 15
 | API-005 | 导出 | 选年月导出;可选乡镇;派生列回写;填表人为当前用户 |
16 16
 | API-005a | 列表已选乡镇后导出 | 导出弹窗所属乡镇与列表一致;传 `townDeptId` 仅该乡镇 |
17 17
 | API-005b | 导出弹窗清空乡镇 | 不传 `townDeptId`,导出全部乡镇 |
18
+| API-006 | 草畜失衡 | 载畜量&lt;存栏绵羊单位 → `biz_yak_disease_warning` 有 `warning_type=6`、`data_source=farmer_household` 记录;改平衡后该预警消失 |
18 19
 | UI-001 | 列表筛选 | 年/月/乡镇 |
19 20
 | UI-002 | 表单村级联 | 只选村;新增默认本年本月 |
20 21
 | UI-003 | 列表选某乡镇后打开导出 | 标签/选项与列表相同,且已选中该乡镇 |

+ 1 - 1
doc/产业数据模型及服务/牦牛疾病预警/牦牛疾病预警技术方案.md

@@ -71,7 +71,7 @@
71 71
 | `3` | 检疫集中预警 |
72 72
 | `4` | 诊疗集中预警 |
73 73
 | `5` | AI问诊集中预警 |
74
-| `6` | 草畜失衡(家庭牧场填报触发,`data_source=family_ranch`) |
74
+| `6` | 草畜失衡(家庭牧场 `data_source=family_ranch`;农牧户 `data_source=farmer_household`) |
75 75
 | `9` | 其他 |
76 76
 
77 77
 第三方无类型码时,仅写 `alert_message`,`warning_type` 可空或由文案解析填充。