From 96cde8ad1629f1e24d39492040a6e5568481f8be Mon Sep 17 00:00:00 2001 From: 戈灵虎 <50576256@qq.com> Date: Fri, 5 Jun 2026 18:23:56 +0800 Subject: [PATCH] feat(garden): 新增行道树巡检功能支持栽种年月和树种类型 --- api_document_tree_inspection.md | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/tree_inspection_planting_date.sql | 21 +++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreePageReqVO.java | 9 ++++++++- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeRespVO.java | 11 ++++++++++- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeSaveReqVO.java | 9 ++++++++- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/treeinspection/TreeInspectionController.java | 8 ++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/AppTreeInspectionController.java | 7 +++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionRespVO.java | 3 +++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionSaveReqVO.java | 7 +++++-- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/convert/treeinspection/TreeInspectionConvert.java | 2 ++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/tree/TreeDO.java | 10 ++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/treeinspection/TreeInspectionDO.java | 5 +++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/tree/TreeMapper.java | 1 + urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/treeinspection/TreeInspectionMapper.java | 12 ++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionService.java | 8 ++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionServiceImpl.java | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 16 files changed, 474 insertions(+), 6 deletions(-) create mode 100644 api_document_tree_inspection.md create mode 100644 sql/tree_inspection_planting_date.sql diff --git a/api_document_tree_inspection.md b/api_document_tree_inspection.md new file mode 100644 index 0000000..5e2daab --- /dev/null +++ b/api_document_tree_inspection.md @@ -0,0 +1,305 @@ +# 行道树巡查需求改造 - 前端接口对接文档 + +> 更新日期:2026-06-05 +> 后端开发:已完成,编译通过 +> 涉及模块:一树一档案、行道树巡检与风险评估 + +--- + +## 一、字段变更总览 + +### 1.1 一树一档案(garden_tree) + +| 变更类型 | 字段名 | 说明 | +|---------|--------|------| +| ⚠️ 废弃 | `estimationtreeage` | 估测树龄,**不再使用**,保留兼容 | +| ✅ 新增 | `plantingDate` | 栽种年月,格式 `yyyy-MM`,如 `"2015-06"` | +| ✅ 新增 | `treeSpeciesType` | 树种类型,**字典值**,字典类型:`tree_species_type` | + +### 1.2 巡检记录(garden_tree_inspection) + +| 变更类型 | 字段名 | 说明 | +|---------|--------|------| +| ⚠️ 废弃 | `weight.plantingYears` | 栽植年限文本选择,**不再使用**,由系统自动计算 | +| ✅ 新增 | `weight.plantingDate` | 栽植年月,格式 `yyyy-MM`,如 `"2015-06"` | + +### 1.3 字典配置 + +| 字典类型 | 字典值 | 标签 | +|---------|--------|------| +| `tree_species_type` | `1` | 深根性树种 | +| `tree_species_type` | `2` | 浅根性树种 | + +> 前端通过通用字典接口获取:`GET /garden/common/dict-type?dict_type=tree_species_type` + +--- + +## 二、一树一档案相关接口变更 + +### 2.1 新增/编辑行道树 + +**接口**:`POST /garden/tree/create` 或 `PUT /garden/tree/update` + +请求体新增字段: + +```json +{ + "id": 1024, + "treenumber": "D0001-P1-0001", + "treetype": "香樟", + "dbh": "30", + + "plantingDate": "2015-06", + "treeSpeciesType": "1", + + "estimationtreeage": null +} +``` + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `plantingDate` | String | 否 | 栽种年月,格式 `yyyy-MM`,替代原 `estimationtreeage` | +| `treeSpeciesType` | String | 否 | 树种类型字典值(`1`=深根性,`2`=浅根性) | +| `estimationtreeage` | String | 否 | **已废弃**,前端应改用 `plantingDate` | + +### 2.2 获取行道树详情 + +**接口**:`GET /garden/tree/get?id={id}` + +响应新增字段: + +```json +{ + "code": 0, + "data": { + "id": 1024, + "treenumber": "D0001-P1-0001", + "estimationtreeage": "10", + + "plantingDate": "2015-06", + "treeSpeciesType": "1", + + "...": "其他字段不变" + } +} +``` + +> **注意**:详情页中原"预估年龄/估测树龄"改为显示"栽种年月",取 `plantingDate` 字段值。`treeSpeciesType` 用字典翻译显示。 + +### 2.3 行道树列表分页(PC端) + +**接口**:`GET /garden/tree/page` + +新增查询参数: + +| 参数 | 类型 | 说明 | +|------|------|------| +| `treeSpeciesType` | String | 树种类型筛选,传字典值(`1` 或 `2`) | + +示例: +``` +GET /garden/tree/page?pageNo=1&pageSize=20&treeSpeciesType=1 +``` + +> 列表中在"胸径"后面新增"树种类别"展示列,值通过字典翻译。 + +--- + +## 三、巡检记录相关接口变更 + +### 3.1 提交巡检记录 + +**接口**:`POST /garden/tree-inspection/create` + +`weight` 对象变更: + +```json +{ + "treeId": 1024, + "inspectionTime": "2026-06-05 14:30:00", + "root": { "disease": 0, "anchorage": 0, "cutting": 0 }, + "collar": { "woodDamage": 5, "barkDamage": 0, "loosening": 0 }, + "trunk": { "woodDamage": 0, "tilt": 0, "barkDamage": 0 }, + "crown": { "looseBranch": 0, "collarAbnormal": 0, "ventilationBalance": 0 }, + "weight": { + "treeSpeciesType": "深根性树种", + "plantingDate": "2015-06", + "isWindCorridor": false, + "treePoolType": "联通树池", + "treePoolWidthDbhRatio": "7 倍及以上" + }, + "result": { + "isEmergency": false, + "windPower": null, + "defectScore": 5, + "normalResult": { "score": 5.0, "level": "I级 (基本无风险)" }, + "emergencyResult": null + }, + "status": { + "photos": ["https://xxx.com/photo1.jpg"] + } +} +``` + +**weight 对象字段说明**: + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `treeSpeciesType` | String | **是** | 树种类型文本:`"深根性树种"` 或 `"浅根性树种"` | +| `plantingDate` | String | 否 | 栽植年月,格式 `yyyy-MM`。**填写后系统自动计算年限和权重** | +| `plantingYears` | String | 否 | **已废弃**,无需传入。后端根据 `plantingDate` 自动计算 | +| `isWindCorridor` | Boolean | **是** | 是否处于风口 | +| `treePoolType` | String | **是** | 树池类型 | +| `treePoolWidthDbhRatio` | String | **是** | 树池宽度与胸径比 | + +**后端自动行为**: +- 根据 `plantingDate` 自动计算栽植年限(10年以内/10-30年/30年以上)和对应权重 +- 提交成功后,自动将 `treeSpeciesType` 和 `plantingDate` **回写**到一树一档案详情 + +### 3.2 获取巡检详情 + +**接口**:`GET /garden/tree-inspection/get?id={id}` + +响应 `weight` 对象新增字段: + +```json +{ + "code": 0, + "data": { + "id": 100, + "treeId": 1024, + "inspectionTime": "2026-06-05 14:30:00", + "weight": { + "treeSpeciesType": "深根性树种", + "treeSpeciesWeight": 1.0, + "plantingYears": "栽植 10-30 年", + "plantingYearsWeight": 1.1, + "plantingDate": "2015-06", + "isWindCorridor": false, + "windCorridorWeight": 1.0, + "treePoolType": "联通树池", + "treePoolWeight": 1.0, + "treePoolWidthDbhRatio": "7 倍及以上", + "treePoolRatioWeight": 1.0 + }, + "...": "其他字段不变" + } +} +``` + +| 新增字段 | 类型 | 说明 | +|---------|------|------| +| `weight.plantingDate` | String | 栽植年月(用户填写的原始值) | +| `weight.plantingYears` | String | 系统自动计算的栽植年限文本 | + +### 3.3 ⭐ 获取最近一次巡检记录(新增接口) + +**接口**:`GET /garden/tree-inspection/latest?treeId={treeId}` + +**用途**:汛期频繁巡检场景,用户提交第一次巡检后,后续每次打开新增界面时调用此接口,**自动带入上一次填写记录**,用户可修改后再提交。 + +**请求参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `treeId` | Long | 是 | 一树一档案ID | + +**响应**: + +```json +{ + "code": 0, + "data": { + "id": 100, + "treeId": 1024, + "treenumber": "D0001-P1-0001", + "inspectionTime": "2026-06-05 14:30:00", + "inspectorId": 10001, + "inspectorName": "张三", + "root": { "disease": 0, "anchorage": 0, "cutting": 0 }, + "collar": { "woodDamage": 5, "barkDamage": 0, "loosening": 0 }, + "trunk": { "woodDamage": 0, "tilt": 0, "barkDamage": 0 }, + "crown": { "looseBranch": 0, "collarAbnormal": 0, "ventilationBalance": 0 }, + "weight": { + "treeSpeciesType": "深根性树种", + "treeSpeciesWeight": 1.0, + "plantingYears": "栽植 10-30 年", + "plantingYearsWeight": 1.1, + "plantingDate": "2015-06", + "isWindCorridor": false, + "windCorridorWeight": 1.0, + "treePoolType": "联通树池", + "treePoolWeight": 1.0, + "treePoolWidthDbhRatio": "7 倍及以上", + "treePoolRatioWeight": 1.0 + }, + "result": { + "isEmergency": false, + "windPower": null, + "windPowerWeight": 1.0, + "defectScore": 5, + "normalResult": { "score": 5.0, "level": "I级 (基本无风险)" }, + "emergencyResult": null + }, + "status": { + "photos": ["https://xxx.com/photo1.jpg"] + } + } +} +``` + +> **特殊情况**:如果该树木没有任何巡检记录,`data` 返回 `null`。 + +**前端处理逻辑**: +1. 用户点击"新增巡检"时,调用 `GET /latest?treeId=xxx` +2. 如果 `data` 不为 `null`,将返回的各字段值预填到表单中(**注意不要预填 `id`、`inspectionTime`、`inspectorId`、`inspectorName` 等系统字段**) +3. 用户可在预填基础上修改,最终提交的数据以用户最后修改为准 + +--- + +## 四、前端改造要点清单 + +### 4.1 PC端-行道树新增/编辑页 + +- [ ] "估测年龄"字段 → 改为"栽种年月",使用**年月选择器**(`yyyy-MM`),绑定 `plantingDate` +- [ ] 新增"树种类型"字段,使用**下拉选择**,数据源为字典 `tree_species_type`,绑定 `treeSpeciesType`,**必选** + +### 4.2 PC端-行道树详情页 + +- [ ] "估测树龄"字段 → 改为显示"栽种年月",取 `plantingDate` 值 +- [ ] 新增"树种类型"展示,`treeSpeciesType` 通过字典翻译显示 + +### 4.3 PC端-行道树列表页 + +- [ ] 检索区域新增"树种类型"筛选项(下拉,数据源为字典 `tree_species_type`) +- [ ] 列表表头在"胸径"后新增"树种类别"列,值通过字典翻译 + +### 4.4 PC端-巡检记录展示 + +- [ ] 第13项"该行道树属于什么树种?"展示 `weight.treeSpeciesType` +- [ ] 第14项"该行道树的栽植年限属于哪一种?"改为展示 `weight.plantingDate`(栽植年月)+ `weight.plantingYears`(自动计算的年限) + +### 4.5 小程序端-树木详情页 + +- [ ] "预估年龄" → 改为"栽植年月",取 `plantingDate` 值 +- [ ] 非必填项中去掉"请输入"三个字的占位文本 + +### 4.6 小程序端-新增行道树录入 + +- [ ] "预估年龄" → 改为"栽种年月",使用年月选择器,绑定 `plantingDate` +- [ ] 新增"树种类型"选择,字典 `tree_species_type` + +### 4.7 小程序端-巡检表单 + +- [ ] 第13项"该行道树属于什么树种?"保持单选(深根性/浅根性),绑定 `weight.treeSpeciesType` +- [ ] 第14项"该行道树的栽植年限?"原三选一 → 改为**年月选择器**,绑定 `weight.plantingDate`,系统自动显示计算出的年限 +- [ ] **汛期预填**:进入新增巡检页面时,调用 `GET /latest?treeId=xxx`,若有数据则预填表单 + +--- + +## 五、注意事项 + +1. `estimationtreeage` 和 `plantingYears` 字段虽然废弃但**后端仍保留兼容**,前端可以分阶段迁移 +2. 巡检提交接口中 `weight.treeSpeciesType` 传的是**文本**("深根性树种"/"浅根性树种"),不是字典值;而一树一档案中 `treeSpeciesType` 存的也是相同文本 +3. `plantingDate` 格式必须严格为 `yyyy-MM`(如 `"2015-06"`),否则后端解析会失败并降级处理 +4. `/latest` 接口返回 `data` 为 `null` 时表示无历史巡检记录,前端应展示空表单 diff --git a/sql/tree_inspection_planting_date.sql b/sql/tree_inspection_planting_date.sql new file mode 100644 index 0000000..df6cbc7 --- /dev/null +++ b/sql/tree_inspection_planting_date.sql @@ -0,0 +1,21 @@ +-- ============================================= +-- 2026年6月 行道树巡查新增需求 数据库变更 +-- ============================================= + +-- 1. garden_tree 表新增字段 +ALTER TABLE garden_tree ADD COLUMN planting_date VARCHAR(10) COMMENT '栽种年月(格式yyyy-MM)'; +ALTER TABLE garden_tree ADD COLUMN tree_species_type VARCHAR(20) COMMENT '树种类型(字典类型:tree_species_type)'; + +-- 2. garden_tree_inspection 表新增字段 +ALTER TABLE garden_tree_inspection ADD COLUMN planting_date VARCHAR(10) COMMENT '栽植年月(格式yyyy-MM)'; + +-- 3. 插入字典类型 +INSERT INTO system_dict_type (name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) +VALUES ('树种类型', 'tree_species_type', 0, '行道树树种类型(深根性/浅根性)', '1', NOW(), '1', NOW(), 0, NULL); + +-- 4. 插入字典数据(注意:dict_type 对应上面的 type 值) +INSERT INTO system_dict_data (sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted, deleted_time) +VALUES (1, '深根性树种', '1', 'tree_species_type', 0, 'default', '', '深根性树种', '1', NOW(), '1', NOW(), 0, NULL); + +INSERT INTO system_dict_data (sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted, deleted_time) +VALUES (2, '浅根性树种', '2', 'tree_species_type', 0, 'default', '', '浅根性树种', '1', NOW(), '1', NOW(), 0, NULL); diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreePageReqVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreePageReqVO.java index c10ec81..8b605f0 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreePageReqVO.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreePageReqVO.java @@ -64,9 +64,16 @@ public class TreePageReqVO extends PageParam { @Schema(description = "数据状态(已更新、未更新)") private String datastate; - @Schema(description = "估测树龄") + @Schema(description = "估测树龄(已废弃)") + @Deprecated private String estimationtreeage; + @Schema(description = "栽种年月(格式yyyy-MM)") + private String plantingDate; + + @Schema(description = "树种类型(字典类型:tree_species_type)") + private String treeSpeciesType; + @Schema(description = "冠幅东西") private String canopyeastwest; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeRespVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeRespVO.java index a55520d..17a5d64 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeRespVO.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeRespVO.java @@ -100,10 +100,19 @@ public class TreeRespVO implements VO { // @ExcelProperty("数据状态(已更新、未更新)") private String datastate; - @Schema(description = "估测树龄") + @Schema(description = "估测树龄(已废弃,请使用plantingDate栽种年月字段)") @ExcelProperty("估测树龄") + @Deprecated private String estimationtreeage; + @Schema(description = "栽种年月(格式yyyy-MM)", example = "2015-06") + @ExcelProperty("栽种年月") + private String plantingDate; + + @Schema(description = "树种类型(字典类型:tree_species_type)", example = "1") + @ExcelProperty("树种类别") + private String treeSpeciesType; + @Schema(description = "冠幅东西") @ExcelProperty("冠幅东西") private String canopyeastwest; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeSaveReqVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeSaveReqVO.java index 726212b..006baf0 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeSaveReqVO.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/tree/vo/TreeSaveReqVO.java @@ -69,9 +69,16 @@ public class TreeSaveReqVO { @Schema(description = "数据状态(已更新、未更新)") private String datastate; - @Schema(description = "估测树龄") + @Schema(description = "估测树龄(已废弃,请使用plantingDate栽种年月字段)") + @Deprecated private String estimationtreeage; + @Schema(description = "栽种年月(格式yyyy-MM)", example = "2015-06") + private String plantingDate; + + @Schema(description = "树种类型(字典类型:tree_species_type)", example = "1") + private String treeSpeciesType; + @Schema(description = "冠幅东西") private String canopyeastwest; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/treeinspection/TreeInspectionController.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/treeinspection/TreeInspectionController.java index c22ebc0..8c5764b 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/treeinspection/TreeInspectionController.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/treeinspection/TreeInspectionController.java @@ -47,4 +47,12 @@ public class TreeInspectionController { return success(respPageResult); } + @GetMapping("/latest") + @Operation(summary = "获取最近一次巡检记录") + @Parameter(name = "treeId", description = "一树一档案ID", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('garden:tree-inspection:query')") + public CommonResult getLatestTreeInspection(@RequestParam("treeId") Long treeId) { + return success(treeInspectionService.getLatestTreeInspection(treeId)); + } + } diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/AppTreeInspectionController.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/AppTreeInspectionController.java index af631d6..1e1d0f7 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/AppTreeInspectionController.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/AppTreeInspectionController.java @@ -50,4 +50,11 @@ public class AppTreeInspectionController { return success(respPageResult); } + @GetMapping("/latest") + @Operation(summary = "获取最近一次巡检记录(汛期频繁巡检预填)") + @Parameter(name = "treeId", description = "一树一档案ID", required = true, example = "1024") + public CommonResult getLatestTreeInspection(@RequestParam("treeId") Long treeId) { + return success(treeInspectionService.getLatestTreeInspection(treeId)); + } + } diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionRespVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionRespVO.java index ef97121..97cf73b 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionRespVO.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionRespVO.java @@ -123,6 +123,9 @@ public class TreeInspectionRespVO { @Schema(description = "栽植年限权重常数", example = "1.1") private Double plantingYearsWeight; + @Schema(description = "栽植年月(格式yyyy-MM)", example = "2015-06") + private String plantingDate; + @Schema(description = "是否处于风口", example = "false") private Boolean isWindCorridor; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionSaveReqVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionSaveReqVO.java index fe973ed..497bdfe 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionSaveReqVO.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/app/treeinspection/vo/TreeInspectionSaveReqVO.java @@ -133,10 +133,13 @@ public class TreeInspectionSaveReqVO { @NotBlank(message = "树种类型不能为空") private String treeSpeciesType; - @Schema(description = "栽植年限:栽植 10 年以内, 栽植 10-30 年, 栽植 30 年以上", requiredMode = Schema.RequiredMode.REQUIRED, example = "栽植 10-30 年") - @NotBlank(message = "栽植年限不能为空") + @Schema(description = "栽植年限(已废弃,请使用plantingDate)", example = "栽植 10-30 年") + @Deprecated private String plantingYears; + @Schema(description = "栽植年月(格式yyyy-MM)", example = "2015-06") + private String plantingDate; + @Schema(description = "是否处于风口", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") @NotNull(message = "是否处于风口标识不能为空") private Boolean isWindCorridor; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/convert/treeinspection/TreeInspectionConvert.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/convert/treeinspection/TreeInspectionConvert.java index 59d8f1b..22680ca 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/convert/treeinspection/TreeInspectionConvert.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/convert/treeinspection/TreeInspectionConvert.java @@ -29,6 +29,7 @@ public interface TreeInspectionConvert { @Mapping(source = "crown.ventilationBalance", target = "crownVentilationBalance"), @Mapping(source = "weight.treeSpeciesType", target = "treeSpeciesType"), @Mapping(source = "weight.plantingYears", target = "plantingYears"), + @Mapping(source = "weight.plantingDate", target = "plantingDate"), @Mapping(source = "weight.isWindCorridor", target = "isWindCorridor"), @Mapping(source = "weight.treePoolType", target = "treePoolType"), @Mapping(source = "weight.treePoolWidthDbhRatio", target = "treePoolWidthDbhRatio"), @@ -60,6 +61,7 @@ public interface TreeInspectionConvert { @Mapping(source = "treeSpeciesWeight", target = "weight.treeSpeciesWeight"), @Mapping(source = "plantingYears", target = "weight.plantingYears"), @Mapping(source = "plantingYearsWeight", target = "weight.plantingYearsWeight"), + @Mapping(source = "plantingDate", target = "weight.plantingDate"), @Mapping(source = "isWindCorridor", target = "weight.isWindCorridor"), @Mapping(source = "windCorridorWeight", target = "weight.windCorridorWeight"), @Mapping(source = "treePoolType", target = "weight.treePoolType"), diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/tree/TreeDO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/tree/TreeDO.java index 4d2771e..2e3b24f 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/tree/TreeDO.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/tree/TreeDO.java @@ -176,6 +176,16 @@ public class TreeDO { */ private Long companyId; + /** + * 栽种年月(格式 yyyy-MM) + */ + private String plantingDate; + + /** + * 树种类型(字典类型:tree_species_type) + */ + private String treeSpeciesType; + @TableField(exist = false) private List treeImgList; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/treeinspection/TreeInspectionDO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/treeinspection/TreeInspectionDO.java index b24ac45..cbe57e3 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/treeinspection/TreeInspectionDO.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/treeinspection/TreeInspectionDO.java @@ -138,6 +138,11 @@ public class TreeInspectionDO extends TenantBaseDO { private String plantingYears; /** + * 栽植年月(格式 yyyy-MM),由用户在巡检时填写 + */ + private String plantingDate; + + /** * 栽植年限权重:10年内-1.0, 10-30年-1.1, 30年以上-1.2 */ private Double plantingYearsWeight; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/tree/TreeMapper.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/tree/TreeMapper.java index 5dd0870..c16c58c 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/tree/TreeMapper.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/tree/TreeMapper.java @@ -47,6 +47,7 @@ public interface TreeMapper extends BaseMapperX { .eqIfPresent(TreeDO::getOldtreeownership, reqVO.getOldtreeownership()) .eqIfPresent(TreeDO::getDatastate, reqVO.getDatastate()) .eqIfPresent(TreeDO::getEstimationtreeage, reqVO.getEstimationtreeage()) + .eqIfPresent(TreeDO::getTreeSpeciesType, reqVO.getTreeSpeciesType()) .eqIfPresent(TreeDO::getCanopyeastwest, reqVO.getCanopyeastwest()) .eqIfPresent(TreeDO::getCanopysouthnorth, reqVO.getCanopysouthnorth()) .eqIfPresent(TreeDO::getWeekday, reqVO.getWeekday()) diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/treeinspection/TreeInspectionMapper.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/treeinspection/TreeInspectionMapper.java index 576664b..544d902 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/treeinspection/TreeInspectionMapper.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/treeinspection/TreeInspectionMapper.java @@ -23,4 +23,16 @@ public interface TreeInspectionMapper extends BaseMapperX { ); } + /** + * 查询某棵树最近一次巡检记录 + */ + default TreeInspectionDO selectLatestByTreeId(Long treeId) { + return selectOne(new LambdaQueryWrapperX() + .eq(TreeInspectionDO::getTreeId, treeId) + .orderByDesc(TreeInspectionDO::getInspectionTime) + .orderByDesc(TreeInspectionDO::getId) + .last("LIMIT 1") + ); + } + } diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionService.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionService.java index a786c9b..af9b7df 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionService.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionService.java @@ -36,4 +36,12 @@ public interface TreeInspectionService { */ PageResult getTreeInspectionPage(TreeInspectionPageReqVO pageReqVO); + /** + * 获取某棵树最近一次巡检记录(用于汛期频繁巡检预填) + * + * @param treeId 一树一档案ID + * @return 最近一次巡检记录的详情 VO,无记录则返回 null + */ + TreeInspectionRespVO getLatestTreeInspection(Long treeId); + } diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionServiceImpl.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionServiceImpl.java index 178b73b..f23638d 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionServiceImpl.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/treeinspection/TreeInspectionServiceImpl.java @@ -4,8 +4,14 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; import jakarta.annotation.Resource; +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + import com.zteits.urbanops.framework.common.pojo.PageResult; import com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil; import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; @@ -61,7 +67,16 @@ public class TreeInspectionServiceImpl implements TreeInspectionService { double treeSpeciesWeight = "浅根性树种".equals(entity.getTreeSpeciesType()) ? 1.1 : 1.0; entity.setTreeSpeciesWeight(treeSpeciesWeight); - double plantingYearsWeight = getPlantingYearsWeight(entity.getPlantingYears()); + // 4.1 如果传入了 plantingDate(栽植年月),自动计算 plantingYears 文本和权重 + double plantingYearsWeight; + if (StringUtils.hasText(entity.getPlantingDate())) { + String autoPlantingYears = calculatePlantingYearsFromDate(entity.getPlantingDate()); + entity.setPlantingYears(autoPlantingYears); + plantingYearsWeight = getPlantingYearsWeight(autoPlantingYears); + } else { + // 兼容旧接口:直接使用 plantingYears 文本 + plantingYearsWeight = getPlantingYearsWeight(entity.getPlantingYears()); + } entity.setPlantingYearsWeight(plantingYearsWeight); double windCorridorWeight = Boolean.TRUE.equals(entity.getIsWindCorridor()) ? 2.0 : 1.0; @@ -134,6 +149,21 @@ public class TreeInspectionServiceImpl implements TreeInspectionService { // 7. 保存到数据库 treeInspectionMapper.insert(entity); + + // 8. 将巡检记录中的树种类型和栽植年月回写到一树一档案 + boolean needUpdateTree = false; + if (StringUtils.hasText(entity.getTreeSpeciesType())) { + tree.setTreeSpeciesType(entity.getTreeSpeciesType()); + needUpdateTree = true; + } + if (StringUtils.hasText(entity.getPlantingDate())) { + tree.setPlantingDate(entity.getPlantingDate()); + needUpdateTree = true; + } + if (needUpdateTree) { + treeMapper.updateById(tree); + } + return entity.getId(); } @@ -151,8 +181,38 @@ public class TreeInspectionServiceImpl implements TreeInspectionService { return treeInspectionMapper.selectPage(pageReqVO); } + @Override + public TreeInspectionRespVO getLatestTreeInspection(Long treeId) { + TreeInspectionDO latest = treeInspectionMapper.selectLatestByTreeId(treeId); + if (latest == null) { + return null; + } + return TreeInspectionConvert.INSTANCE.convert(latest); + } + // ========== 权重因子规则辅助类 ========== + /** + * 根据栽植年月(yyyy-MM)计算栽植年限文本 + */ + private String calculatePlantingYearsFromDate(String plantingDate) { + try { + YearMonth planting = YearMonth.parse(plantingDate, DateTimeFormatter.ofPattern("yyyy-MM")); + YearMonth now = YearMonth.now(); + long years = ChronoUnit.YEARS.between(planting, now); + if (years < 10) { + return "栽植 10 年以内"; + } else if (years <= 30) { + return "栽植 10-30 年"; + } else { + return "栽植 30 年以上"; + } + } catch (Exception e) { + log.warn("解析栽植年月失败: {}", plantingDate, e); + return null; + } + } + private double getPlantingYearsWeight(String years) { if (years == null) return 1.0; if (years.contains("30年")) return 1.2; -- libgit2 0.21.4