From d531bc7901a3f60a81e1ccd36ff6cea6ef7332eb Mon Sep 17 00:00:00 2001 From: 王彪总 Date: Mon, 22 Jun 2026 14:57:53 +0800 Subject: [PATCH] feat(garden): 新增城市部件管理功能并调整生产环境日志级别 --- docs/城市部件-功能设计方案.md | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/城市部件-建表SQL.sql | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/城市部件-菜单SQL.sql | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/CityComponentController.java | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentExportVO.java | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentImportVO.java | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentPageReqVO.java | 29 +++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentRespVO.java | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentSaveReqVO.java | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/CityComponentTypeController.java | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypePageReqVO.java | 28 ++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeRespVO.java | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeSaveReqVO.java | 38 ++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponent/CityComponentDO.java | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponenttype/CityComponentTypeDO.java | 30 ++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponent/CityComponentMapper.java | 40 ++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponenttype/CityComponentTypeMapper.java | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/ErrorCodeConstants.java | 10 ++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentService.java | 26 ++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentServiceImpl.java | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeService.java | 30 ++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeServiceImpl.java | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/resources/templates/一物一码属性表导入模版.xlsx | Bin 0 -> 13200 bytes urbanops-server/src/main/resources/application-prod.yaml | 10 +++++----- 24 files changed, 1886 insertions(+), 5 deletions(-) create mode 100644 docs/城市部件-功能设计方案.md create mode 100644 docs/城市部件-建表SQL.sql create mode 100644 docs/城市部件-菜单SQL.sql create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/CityComponentController.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentExportVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentImportVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentPageReqVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentRespVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentSaveReqVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/CityComponentTypeController.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypePageReqVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeRespVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeSaveReqVO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponent/CityComponentDO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponenttype/CityComponentTypeDO.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponent/CityComponentMapper.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponenttype/CityComponentTypeMapper.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentService.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentServiceImpl.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeService.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeServiceImpl.java create mode 100644 urbanops-module-garden/src/main/resources/templates/一物一码属性表导入模版.xlsx diff --git a/docs/城市部件-功能设计方案.md b/docs/城市部件-功能设计方案.md new file mode 100644 index 0000000..b5fd190 --- /dev/null +++ b/docs/城市部件-功能设计方案.md @@ -0,0 +1,227 @@ +# 城市部件 — 功能设计方案 + +> 基于「西单项目一物一码模型命名规则」设计。资产 ID 编码规则参考西单北大街一物一码属性信息表。 + +--- + +## 一、菜单结构 + +``` +城市部件(一级目录) +├── 城市部件类型(二级菜单) +│ ├── 查询 garden:city-component-type:query +│ ├── 新增 garden:city-component-type:create +│ ├── 修改 garden:city-component-type:update +│ └── 删除 garden:city-component-type:delete +└── 城市部件管理(二级菜单) + ├── 查询 garden:city-component:query + ├── 新增 garden:city-component:create + ├── 修改 garden:city-component:update + ├── 删除 garden:city-component:delete + └── 导出 garden:city-component:export +``` + +--- + +## 二、部件编码规则(一物一码) + +### 2.1 资产 ID 格式 + +``` +{城市代码}{城区代码}{街道代码}_{道路编码}_{类型编码}_{顺序号} +``` + +**示例**:`110102001_02_0211_0001` + +| 段 | 值 | 含义 | +|----|-----|------| +| 110 | 北京市 | 城市代码 | +| 102 | 西城区 | 城区代码 | +| 001 | 西长安街街道 | 街道代码 | +| 02 | 西单北大街 | 道路编码 | +| 0211 | 公共设施>照明灯>路灯 | 三级类型编码 | +| 0001 | 第1个 | 顺序号(4位,同前缀递增) | + +### 2.2 类型编码层级规则 + +| 层级 | 位数 | 示例 | 规则 | +|------|------|------|------| +| 一级 | 2位 | `02` | 公共设施要素 | +| 二级 | 3位 | `021` | 照明灯 = 一级编码 `02` + 序号 `1` | +| 三级 | 4位 | `0211` | 路灯 = 二级编码 `021` + 序号 `1` | + +### 2.3 一级分类(来自命名规则) + +| 编码 | 名称 | +|------|------| +| 01 | 建筑要素 | +| 02 | 公共设施要素 | +| 03 | 园林绿化要素 | +| 04 | 道路交通要素 | + +### 2.4 二级/三级分类示例(公共设施要素 `02` 下) + +| 二级编码 | 二级名称 | 三级编码 | 三级名称 | +|----------|----------|----------|----------| +| 021 | 照明灯 | 0211 | 路灯 | +| | | 0212 | 投光灯 | +| 022 | 摄像头 | 0221 | 球机 | +| | | 0222 | 枪机 | +| | | 0223 | 半球 | +| 023 | 井盖 | 0231 | 电力 | +| | | 0232 | 污水 | +| | | ... | ... | +| 024 | 宣传栏 | 0241 | 立式 | +| | | 0242 | 壁挂式 | +| 025 | 垃圾桶 | 0251 | 单桶 | +| | | 0252 | 双桶 | +| 026 | 下水道口 | 0261 | 平篦 | +| | | 0262 | 立篦 | +| 027 | 路障 | 0271 | 隔离墩 | +| | | 0272 | 防撞桶 | +| 028 | 变电箱 | 0281 | 配电箱 | +| | | 0282 | 变电箱 | +| | | 0283 | 控制箱 | +| 029 | 街道家具 | 0291 | 座椅 | +| | | 0292 | 花箱 | +| | | ... | ... | + +--- + +## 三、数据库设计 + +### 3.1 城市部件类型表 `garden_city_component_type` + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | bigint PK | 主键 | +| type_code | varchar(32) UNIQUE | 类型编码(2/3/4位数字,如 02、021、0211) | +| type_name | varchar(64) | 类型名称 | +| level | tinyint | 1=一级(2位), 2=二级(3位), 3=三级(4位) | +| parent_code | varchar(32) | 父级编码(一级为 NULL) | +| sort | int | 排序 | +| status | tinyint | 1启用 0禁用 | +| remark | varchar(512) | 备注 | +| + 通用字段 | — | creator/create_time/updater/update_time/deleted/tenant_id | + +**编码生成规则**: +- 一级:`{01..99}`,取当前最大一级编码+1(如已有 01~04,新增为 05) +- 二级:`{父级编码}{1..9}`,如父级 `02`,取当前最大二级序号+1 +- 三级:`{父级编码}{1..9}`,如父级 `021`,取当前最大三级序号+1 + +### 3.2 城市部件管理表 `garden_city_component` + +| 字段分组 | 字段 | 类型 | 说明 | +|----------|------|------|------| +| **编码** | component_code | varchar(64) UNIQUE | 资产 ID(一物一码) | +| **类型** | level_one_type_code | varchar(32) | 一级类型编码 | +| | level_one_type_name | varchar(64) | 一级类型名称(冗余) | +| | level_two_type_code | varchar(32) | 二级类型编码 | +| | level_two_type_name | varchar(64) | 二级类型名称(冗余) | +| | level_three_type_code | varchar(32) | 三级类型编码 | +| | level_three_type_name | varchar(64) | 三级类型名称(冗余) | +| **行政区划** | city_code | varchar(16) | 城市代码 | +| | district_code | varchar(16) | 城区代码 | +| | street_code | varchar(16) | 街道代码 | +| **位置** | area | varchar(128) | 所属区域 | +| | road_code | varchar(16) | 道路编码 | +| | road_name | varchar(128) | 道路名称 | +| | x_coord | decimal(12,8) | X(WGS84 经度) | +| | y_coord | decimal(12,8) | Y(WGS84 纬度) | +| | z_coord | decimal(10,4) | Z(高程) | +| | longitude_amap | decimal(12,8) | 高德经度(GCJ02,自动转换) | +| | latitude_amap | decimal(12,8) | 高德纬度(GCJ02,自动转换) | +| | install_orientation | varchar(32) | 安装方位(人行道/车行道/绿化带) | +| | grid | varchar(128) | 所属网格 | +| **设备** | brand | varchar(128) | 品牌/厂家 | +| | model_spec | varchar(128) | 型号规格 | +| | material | varchar(64) | 材质 | +| | length/width/height | decimal(10,2) | 长/宽/高(cm) | +| | dbh | decimal(10,2) | 胸径(cm,树木专用) | +| **生命周期** | install_date | date | 安装/种植时间 | +| | asset_status | varchar(32) | 资产状态 | +| | management_unit | varchar(128) | 管理单位 | +| | responsible_person | varchar(64) | 责任人 | +| | service_years | decimal(4,1) | 投入年限 | +| | maintenance_deadline | date | 维保到期日 | +| | procurement_batch | varchar(128) | 采购批次/项目名称 | +| **巡检** | inspection_cycle | varchar(32) | 巡检周期(日/周/月/季) | +| | last_inspection_time | datetime | 最近巡检时间 | +| | inspector | varchar(64) | 巡检人员 | +| | inspection_result | varchar(32) | 巡检结果(正常/异常/损坏/丢失) | +| | abnormal_description | varchar(512) | 异常描述 | +| **维修** | repair_order_no | varchar(64) | 报修工单编号 | +| | repair_complete_time | datetime | 维修完成时间 | +| | repair_unit | varchar(128) | 维修单位 | +| **其他** | remark | varchar(512) | 备注 | +| | qr_code_url | varchar(512) | 二维码 URL | +| **通用** | — | — | creator/create_time/updater/update_time/deleted/tenant_id | + +--- + +## 四、后端接口 + +### 4.1 城市部件类型 + +| 方法 | URL | 说明 | +|------|-----|------| +| POST | `/garden/city-component-type/create` | 新增 | +| PUT | `/garden/city-component-type/update` | 修改 | +| DELETE | `/garden/city-component-type/delete?id=` | 删除 | +| GET | `/garden/city-component-type/get?id=` | 详情 | +| GET | `/garden/city-component-type/page` | 分页列表(级联筛选) | +| GET | `/garden/city-component-type/list-by-parent` | 按父级查子级 | +| GET | `/garden/city-component-type/generate-next-code` | 生成下级编码 | +| GET | `/garden/city-component-type/tree` | 完整三级树 | + +### 4.2 城市部件管理 + +| 方法 | URL | 说明 | +|------|-----|------| +| POST | `/garden/city-component/create` | 新增(自动坐标转换) | +| PUT | `/garden/city-component/update` | 修改 | +| DELETE | `/garden/city-component/delete?id=` | 删除 | +| GET | `/garden/city-component/get?id=` | 详情 | +| GET | `/garden/city-component/page` | 分页列表 | +| GET | `/garden/city-component/export-excel` | 导出 Excel | +| GET | `/garden/city-component/generate-qr` | 生成二维码 | + +--- + +## 五、坐标转换 + +- 复用 `GisCoordinateUtil.wgs84ToGcj02(x, y)` 将 WGS84 转 GCJ02 +- create/update 时若 X/Y 有值,自动计算高德经纬度 + +--- + +## 六、文件清单 + +### 后端(garden 模块) + +**类型**:`CityComponentTypeDO` / `CityComponentTypeMapper` / `CityComponentTypeService` / `CityComponentTypeServiceImpl` / `CityComponentTypeController` + 3 个 VO + +**部件**:`CityComponentDO` / `CityComponentMapper` / `CityComponentService` / `CityComponentServiceImpl` / `CityComponentController` + 4 个 VO + +### 前端 + +**类型**:`src/api/garden/cityComponentType/index.ts` + `src/views/garden/cityComponentType/` (index.vue + form) + +**部件**:`src/api/garden/cityComponent/index.ts` + `src/views/garden/cityComponent/` (index.vue + form) + +### SQL + +- `docs/城市部件-建表SQL.sql` +- `docs/城市部件-菜单SQL.sql` + +--- + +## 七、实现顺序 + +1. 建表 DDL +2. 城市部件类型后端 + 编译验证 +3. 城市部件类型前端 +4. 城市部件管理后端 + 编译验证 +5. 城市部件管理前端 +6. 菜单 SQL +7. 整体验证 diff --git a/docs/城市部件-建表SQL.sql b/docs/城市部件-建表SQL.sql new file mode 100644 index 0000000..4541fb2 --- /dev/null +++ b/docs/城市部件-建表SQL.sql @@ -0,0 +1,223 @@ +-- ===================================================== +-- 城市部件 — 建表 SQL +-- 数据库:urban_ops_agent (MySQL 8.x) +-- 参考:西单项目一物一码模型命名规则 +-- ===================================================== + +-- 1. 城市部件类型表 +DROP TABLE IF EXISTS `garden_city_component_type`; +CREATE TABLE `garden_city_component_type` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `type_code` varchar(32) NOT NULL COMMENT '类型编码(2/3/4位数字,如 02、021、0211)', + `type_name` varchar(64) NOT NULL COMMENT '类型名称', + `level` tinyint NOT NULL COMMENT '层级:1=一级(2位) 2=二级(3位) 3=三级(4位)', + `parent_code` varchar(32) DEFAULT NULL COMMENT '父级类型编码(一级为NULL)', + `sort` int DEFAULT 0 COMMENT '排序序号', + `status` tinyint DEFAULT 1 COMMENT '状态:1启用 0禁用', + `remark` varchar(512) DEFAULT NULL COMMENT '备注', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '逻辑删除', + `tenant_id` bigint DEFAULT 0 COMMENT '租户ID', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_type_code` (`type_code`), + KEY `idx_parent_code` (`parent_code`), + KEY `idx_level` (`level`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='城市部件类型三级分类表'; + +-- 初始化一级类型(来自西单项目一物一码模型命名规则) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('01', '建筑要素', 1, NULL, 1, 1, '1', '1'), +('02', '公共设施要素', 1, NULL, 2, 1, '1', '1'), +('03', '园林绿化要素', 1, NULL, 3, 1, '1', '1'), +('04', '道路交通要素', 1, NULL, 4, 1, '1', '1'); + +-- 初始化二级类型(公共设施要素 02 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('021', '照明灯', 2, '02', 1, 1, '1', '1'), +('022', '摄像头', 2, '02', 2, 1, '1', '1'), +('023', '井盖', 2, '02', 3, 1, '1', '1'), +('024', '宣传栏', 2, '02', 4, 1, '1', '1'), +('025', '垃圾桶', 2, '02', 5, 1, '1', '1'), +('026', '下水道口', 2, '02', 6, 1, '1', '1'), +('027', '路障', 2, '02', 7, 1, '1', '1'), +('028', '变电箱', 2, '02', 8, 1, '1', '1'), +('029', '街道家具', 2, '02', 9, 1, '1', '1'); + +-- 初始化二级类型(道路交通要素 04 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('041', '栏杆', 2, '04', 1, 1, '1', '1'), +('042', '标识牌', 2, '04', 2, 1, '1', '1'), +('043', '公交站牌', 2, '04', 3, 1, '1', '1'), +('044', '红绿灯', 2, '04', 4, 1, '1', '1'); + +-- 初始化二级类型(园林绿化要素 03 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('031', '花坛', 2, '03', 1, 1, '1', '1'), +('032', '树木', 2, '03', 2, 1, '1', '1'), +('034', '绿化带', 2, '03', 3, 1, '1', '1'); + +-- 初始化三级类型(照明灯 021 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0211', '路灯', 3, '021', 1, 1, '1', '1'), +('0212', '投光灯', 3, '021', 2, 1, '1', '1'); + +-- 初始化三级类型(摄像头 022 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0221', '球机', 3, '022', 1, 1, '1', '1'), +('0222', '枪机', 3, '022', 2, 1, '1', '1'), +('0223', '半球', 3, '022', 3, 1, '1', '1'); + +-- 初始化三级类型(井盖 023 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0231', '电力', 3, '023', 1, 1, '1', '1'), +('0232', '污水', 3, '023', 2, 1, '1', '1'), +('0233', '排水', 3, '023', 3, 1, '1', '1'), +('0234', '通信', 3, '023', 4, 1, '1', '1'), +('0235', '雨水', 3, '023', 5, 1, '1', '1'), +('0236', '消防', 3, '023', 6, 1, '1', '1'), +('0237', '热力', 3, '023', 7, 1, '1', '1'), +('0238', '自来水', 3, '023', 8, 1, '1', '1'), +('0239', '其他', 3, '023', 9, 1, '1', '1'); + +-- 初始化三级类型(宣传栏 024 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0241', '立式', 3, '024', 1, 1, '1', '1'), +('0242', '壁挂式', 3, '024', 2, 1, '1', '1'); + +-- 初始化三级类型(垃圾桶 025 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0251', '单桶', 3, '025', 1, 1, '1', '1'), +('0252', '双桶', 3, '025', 2, 1, '1', '1'), +('0253', '三桶', 3, '025', 3, 1, '1', '1'); + +-- 初始化三级类型(下水道口 026 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0261', '平篦', 3, '026', 1, 1, '1', '1'), +('0262', '立篦', 3, '026', 2, 1, '1', '1'); + +-- 初始化三级类型(路障 027 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0271', '隔离墩', 3, '027', 1, 1, '1', '1'), +('0272', '防撞桶', 3, '027', 2, 1, '1', '1'); + +-- 初始化三级类型(变电箱 028 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0281', '配电箱', 3, '028', 1, 1, '1', '1'), +('0282', '变电箱', 3, '028', 2, 1, '1', '1'), +('0283', '控制箱', 3, '028', 3, 1, '1', '1'); + +-- 初始化三级类型(街道家具 029 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0291', '座椅', 3, '029', 1, 1, '1', '1'), +('0292', '花箱', 3, '029', 2, 1, '1', '1'), +('0293', '健身器材', 3, '029', 3, 1, '1', '1'), +('0294', '亭体', 3, '029', 4, 1, '1', '1'), +('0295', '景观设施', 3, '029', 5, 1, '1', '1'), +('0296', '应急救援', 3, '029', 6, 1, '1', '1'); + +-- 初始化三级类型(栏杆 041 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0411', '人行道护栏', 3, '041', 1, 1, '1', '1'), +('0412', '隔离护栏', 3, '041', 2, 1, '1', '1'), +('0413', '河道护栏', 3, '041', 3, 1, '1', '1'); + +-- 初始化三级类型(标识牌 042 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0421', '指示牌', 3, '042', 1, 1, '1', '1'), +('0422', '警示牌', 3, '042', 2, 1, '1', '1'), +('0423', '路名牌', 3, '042', 3, 1, '1', '1'), +('0424', '禁令牌', 3, '042', 4, 1, '1', '1'); + +-- 初始化三级类型(公交站牌 043 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0431', '候车亭', 3, '043', 1, 1, '1', '1'), +('0432', '简易站牌', 3, '043', 2, 1, '1', '1'); + +-- 初始化三级类型(红绿灯 044 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0441', '机动车灯', 3, '044', 1, 1, '1', '1'), +('0442', '行人灯', 3, '044', 2, 1, '1', '1'), +('0443', '组合灯', 3, '044', 3, 1, '1', '1'); + +-- 初始化三级类型(树木 032 下) +INSERT INTO `garden_city_component_type` (`type_code`, `type_name`, `level`, `parent_code`, `sort`, `status`, `creator`, `updater`) VALUES +('0321', '松树', 3, '032', 1, 1, '1', '1'), +('0322', '杨树', 3, '032', 2, 1, '1', '1'); + +-- ===================================================== +-- 2. 城市部件管理表 +DROP TABLE IF EXISTS `garden_city_component`; +CREATE TABLE `garden_city_component` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `component_code` varchar(64) NOT NULL COMMENT '资产ID(一物一码,如 110102001_02_0211_0001)', + -- 三级类型关联 + `level_one_type_code` varchar(32) DEFAULT NULL COMMENT '一级资产类型编码', + `level_one_type_name` varchar(64) DEFAULT NULL COMMENT '一级资产类型名称(冗余)', + `level_two_type_code` varchar(32) DEFAULT NULL COMMENT '二级资产类型编码', + `level_two_type_name` varchar(64) DEFAULT NULL COMMENT '二级资产类型名称(冗余)', + `level_three_type_code` varchar(32) DEFAULT NULL COMMENT '三级资产类型编码', + `level_three_type_name` varchar(64) DEFAULT NULL COMMENT '三级资产类型名称(冗余)', + -- 行政区划 + `city_code` varchar(16) DEFAULT NULL COMMENT '城市代码', + `district_code` varchar(16) DEFAULT NULL COMMENT '城区代码', + `street_code` varchar(16) DEFAULT NULL COMMENT '街道代码', + -- 位置信息 + `area` varchar(128) DEFAULT NULL COMMENT '所属区域', + `road_code` varchar(16) DEFAULT NULL COMMENT '道路编码', + `road_name` varchar(128) DEFAULT NULL COMMENT '道路名称', + `x_coord` decimal(12,8) DEFAULT NULL COMMENT 'X坐标(WGS84经度)', + `y_coord` decimal(12,8) DEFAULT NULL COMMENT 'Y坐标(WGS84纬度)', + `z_coord` decimal(10,4) DEFAULT NULL COMMENT 'Z坐标(高程)', + `longitude_amap` decimal(12,8) DEFAULT NULL COMMENT '高德经度(GCJ02,自动转换)', + `latitude_amap` decimal(12,8) DEFAULT NULL COMMENT '高德纬度(GCJ02,自动转换)', + `install_orientation` varchar(32) DEFAULT NULL COMMENT '安装方位(人行道/车行道/绿化带)', + `grid` varchar(128) DEFAULT NULL COMMENT '所属网格(城管网格/社区网格编号)', + -- 设备信息 + `brand` varchar(128) DEFAULT NULL COMMENT '品牌/厂家', + `model_spec` varchar(128) DEFAULT NULL COMMENT '型号规格', + `material` varchar(64) DEFAULT NULL COMMENT '材质', + `length` decimal(10,2) DEFAULT NULL COMMENT '长(cm)', + `width` decimal(10,2) DEFAULT NULL COMMENT '宽(cm)', + `height` decimal(10,2) DEFAULT NULL COMMENT '高(cm)', + `dbh` decimal(10,2) DEFAULT NULL COMMENT '胸径(cm,树木专用)', + -- 时间/生命周期 + `install_date` date DEFAULT NULL COMMENT '安装时间/种植时间', + `asset_status` varchar(32) DEFAULT NULL COMMENT '资产状态(在用/停用/报废等)', + `management_unit` varchar(128) DEFAULT NULL COMMENT '管理单位', + `responsible_person` varchar(64) DEFAULT NULL COMMENT '责任人', + `service_years` decimal(4,1) DEFAULT NULL COMMENT '投入年限', + `maintenance_deadline` date DEFAULT NULL COMMENT '维保到期日', + `procurement_batch` varchar(128) DEFAULT NULL COMMENT '采购批次/项目名称', + -- 巡检信息 + `inspection_cycle` varchar(32) DEFAULT NULL COMMENT '巡检周期(日/周/月/季)', + `last_inspection_time` datetime DEFAULT NULL COMMENT '最近巡检时间', + `inspector` varchar(64) DEFAULT NULL COMMENT '巡检人员', + `inspection_result` varchar(32) DEFAULT NULL COMMENT '巡检结果(正常/异常/损坏/丢失)', + `abnormal_description` varchar(512) DEFAULT NULL COMMENT '异常描述', + -- 维修信息 + `repair_order_no` varchar(64) DEFAULT NULL COMMENT '报修工单编号', + `repair_complete_time` datetime DEFAULT NULL COMMENT '维修完成时间', + `repair_unit` varchar(128) DEFAULT NULL COMMENT '维修单位', + -- 其他 + `remark` varchar(512) DEFAULT NULL COMMENT '备注', + `qr_code_url` varchar(512) DEFAULT NULL COMMENT '二维码URL', + `image_urls` varchar(2000) DEFAULT NULL COMMENT '图片URL(多图逗号分隔)', + -- 通用字段 + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '逻辑删除', + `tenant_id` bigint DEFAULT 0 COMMENT '租户ID', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_component_code` (`component_code`), + KEY `idx_level_one_type` (`level_one_type_code`), + KEY `idx_level_two_type` (`level_two_type_code`), + KEY `idx_level_three_type` (`level_three_type_code`), + KEY `idx_road_code` (`road_code`), + KEY `idx_area` (`area`), + KEY `idx_asset_status` (`asset_status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='城市部件管理表(一物一码)'; diff --git a/docs/城市部件-菜单SQL.sql b/docs/城市部件-菜单SQL.sql new file mode 100644 index 0000000..17a9e9f --- /dev/null +++ b/docs/城市部件-菜单SQL.sql @@ -0,0 +1,71 @@ +-- ===================================================== +-- 城市部件 — 菜单 + 按钮权限 SQL +-- 使用 LAST_INSERT_ID 避免ID冲突,NOT EXISTS 防止重复 +-- ===================================================== + +-- 一级菜单 +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件', '', 1, 10, 0, '/city-component', 'ep:component', '', 'CityComponent', 0, b'1', b'0', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name='城市部件' AND type=1 AND deleted=0); + +SET @parent_id = (SELECT id FROM system_menu WHERE name='城市部件' AND type=1 AND deleted=0 LIMIT 1); + +-- 城市部件类型 +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件类型', '', 2, 1, @parent_id, 'city-component-type', 'ep:list', 'garden/cityComponentType/index', 'CityComponentType', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name='城市部件类型' AND parent_id=@parent_id AND deleted=0); + +-- 城市部件管理 +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件管理', '', 2, 2, @parent_id, 'city-component', 'ep:grid', 'garden/cityComponent/index', 'CityComponent', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name='城市部件管理' AND parent_id=@parent_id AND deleted=0); + +SET @type_menu_id = (SELECT id FROM system_menu WHERE name='城市部件类型' AND parent_id=@parent_id AND deleted=0 LIMIT 1); +SET @comp_menu_id = (SELECT id FROM system_menu WHERE name='城市部件管理' AND parent_id=@parent_id AND deleted=0 LIMIT 1); + +-- 城市部件类型按钮 +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件类型查询', 'garden:city-component-type:query', 3, 1, @type_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component-type:query' AND deleted=0); + +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件类型新增', 'garden:city-component-type:create', 3, 2, @type_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component-type:create' AND deleted=0); + +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件类型修改', 'garden:city-component-type:update', 3, 3, @type_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component-type:update' AND deleted=0); + +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件类型删除', 'garden:city-component-type:delete', 3, 4, @type_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component-type:delete' AND deleted=0); + +-- 城市部件管理按钮 +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件查询', 'garden:city-component:query', 3, 1, @comp_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component:query' AND deleted=0); + +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件新增', 'garden:city-component:create', 3, 2, @comp_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component:create' AND deleted=0); + +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件修改', 'garden:city-component:update', 3, 3, @comp_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component:update' AND deleted=0); + +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件删除', 'garden:city-component:delete', 3, 4, @comp_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component:delete' AND deleted=0); + +INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) +SELECT '城市部件导出', 'garden:city-component:export', 3, 5, @comp_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE permission='garden:city-component:export' AND deleted=0); + +-- 赋权超级管理员 +INSERT IGNORE INTO system_role_menu (role_id, menu_id, creator, create_time, updater, update_time) +SELECT 1, id, '1', NOW(), '1', NOW() FROM system_menu +WHERE id IN (@parent_id, @type_menu_id, @comp_menu_id) AND deleted=0; + +INSERT IGNORE INTO system_role_menu (role_id, menu_id, creator, create_time, updater, update_time) +SELECT 1, id, '1', NOW(), '1', NOW() FROM system_menu +WHERE parent_id IN (@type_menu_id, @comp_menu_id) AND deleted=0; diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/CityComponentController.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/CityComponentController.java new file mode 100644 index 0000000..569c89f --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/CityComponentController.java @@ -0,0 +1,181 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponent; + +import cn.idev.excel.FastExcelFactory; +import com.zteits.urbanops.framework.excel.core.handler.ColumnWidthMatchStyleStrategy; +import com.zteits.urbanops.framework.excel.core.handler.SelectSheetWriteHandler; +import com.zteits.urbanops.framework.excel.core.util.ExcelUtils; +import com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo.*; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponent.CityComponentDO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponenttype.CityComponentTypeDO; +import com.zteits.urbanops.module.garden.dal.mysql.citycomponenttype.CityComponentTypeMapper; +import com.zteits.urbanops.module.garden.service.citycomponent.CityComponentService; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.*; +import jakarta.servlet.http.HttpServletResponse; + +import java.math.BigDecimal; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +import com.zteits.urbanops.framework.common.pojo.CommonResult; +import com.zteits.urbanops.framework.common.pojo.PageResult; +import com.zteits.urbanops.framework.common.util.object.BeanUtils; +import static com.zteits.urbanops.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 城市部件管理") +@RestController +@RequestMapping("/garden/city-component") +@Validated +public class CityComponentController { + + @Resource + private CityComponentService cityComponentService; + @Resource + private CityComponentTypeMapper cityComponentTypeMapper; + + @PostMapping("/create") + @Operation(summary = "新增城市部件") + @PreAuthorize("@ss.hasPermission('garden:city-component:create')") + public CommonResult create(@Valid @RequestBody CityComponentSaveReqVO reqVO) { + return success(cityComponentService.create(reqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改城市部件") + @PreAuthorize("@ss.hasPermission('garden:city-component:update')") + public CommonResult update(@Valid @RequestBody CityComponentSaveReqVO reqVO) { + cityComponentService.update(reqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除城市部件") + @PreAuthorize("@ss.hasPermission('garden:city-component:delete')") + public CommonResult delete(@RequestParam("id") Long id) { + cityComponentService.delete(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得城市部件") + @PreAuthorize("@ss.hasPermission('garden:city-component:query')") + public CommonResult get(@RequestParam("id") Long id) { + return success(BeanUtils.toBean(cityComponentService.get(id), CityComponentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得城市部件分页") + @PreAuthorize("@ss.hasPermission('garden:city-component:query')") + public CommonResult> getPage(@Valid CityComponentPageReqVO reqVO) { + PageResult pageResult = cityComponentService.getPage(reqVO); + return success(BeanUtils.toBean(pageResult, CityComponentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出城市部件 Excel") + @PreAuthorize("@ss.hasPermission('garden:city-component:export')") + public void exportExcel(@Valid CityComponentPageReqVO reqVO, HttpServletResponse response) throws IOException { + List list = cityComponentService.getList(reqVO); + List exportList = BeanUtils.toBean(list, CityComponentExportVO.class); + String filename = "城市部件" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ".xlsx"; + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Content-disposition", + "attachment;filename*=utf-8''" + URLEncoder.encode(filename, StandardCharsets.UTF_8)); + FastExcelFactory.write(response.getOutputStream(), CityComponentExportVO.class) + .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) + .registerWriteHandler(new SelectSheetWriteHandler(CityComponentExportVO.class)) + .sheet("数据").doWrite(exportList); + } + + @GetMapping("/generate-qr") + @Operation(summary = "生成二维码") + @PreAuthorize("@ss.hasPermission('garden:city-component:update')") + public CommonResult generateQr(@RequestParam("id") Long id) { + return success(cityComponentService.generateQrCode(id)); + } + + @GetMapping("/import-template") + @Operation(summary = "下载导入模板") + @jakarta.annotation.security.PermitAll + public void downloadImportTemplate(HttpServletResponse response) throws IOException { + String filename = "一物一码属性表导入模版.xlsx"; + org.springframework.core.io.Resource resource = new org.springframework.core.io.ClassPathResource("templates/" + filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(filename, StandardCharsets.UTF_8)); + org.springframework.util.StreamUtils.copy(resource.getInputStream(), response.getOutputStream()); + } + + @PostMapping("/import") + @Operation(summary = "导入城市部件") + @PreAuthorize("@ss.hasPermission('garden:city-component:create')") + public CommonResult importExcel(@RequestParam("file") MultipartFile file) throws IOException { + List importList = FastExcelFactory.read(file.getInputStream()) + .head(CityComponentImportVO.class).headRowNumber(1).sheet().doReadSync(); + List errors = new ArrayList<>(); + // 第一遍:全量校验 + for (int i = 0; i < importList.size(); i++) { + CityComponentImportVO vo = importList.get(i); + int row = i + 2; + if (vo.getComponentCode() == null || vo.getComponentCode().isEmpty()) { errors.add("第"+row+"行: 资产ID不能为空"); continue; } + // 验证类型名称 + CityComponentTypeDO t1 = null, t2 = null, t3 = null; + if (vo.getLevelOneTypeName() != null && !vo.getLevelOneTypeName().isEmpty()) { + t1 = cityComponentTypeMapper.selectByNameAndParentAndLevel(vo.getLevelOneTypeName(), null, 1); + if (t1 == null) { errors.add("第"+row+"行: 一级资产类型「"+vo.getLevelOneTypeName()+"」不存在"); continue; } + } + if (vo.getLevelTwoTypeName() != null && !vo.getLevelTwoTypeName().isEmpty()) { + t2 = cityComponentTypeMapper.selectByNameAndParentAndLevel(vo.getLevelTwoTypeName(), t1!=null?t1.getTypeCode():null, 2); + if (t2 == null) { errors.add("第"+row+"行: 二级资产类型「"+vo.getLevelTwoTypeName()+"」不存在"); continue; } + } + if (vo.getLevelThreeTypeName() != null && !vo.getLevelThreeTypeName().isEmpty()) { + t3 = cityComponentTypeMapper.selectByNameAndParentAndLevel(vo.getLevelThreeTypeName(), t2!=null?t2.getTypeCode():null, 3); + if (t3 == null) { errors.add("第"+row+"行: 三级资产类型「"+vo.getLevelThreeTypeName()+"」不存在"); continue; } + } + } + if (!errors.isEmpty()) { + return success("校验失败: " + String.join("; ", errors.subList(0, Math.min(errors.size(), 10)))); + } + // 第二遍:逐条导入 + int count = 0; + for (CityComponentImportVO vo : importList) { + CityComponentTypeDO t1 = vo.getLevelOneTypeName()!=null ? cityComponentTypeMapper.selectByNameAndParentAndLevel(vo.getLevelOneTypeName(), null, 1) : null; + CityComponentTypeDO t2 = vo.getLevelTwoTypeName()!=null ? cityComponentTypeMapper.selectByNameAndParentAndLevel(vo.getLevelTwoTypeName(), t1!=null?t1.getTypeCode():null, 2) : null; + CityComponentTypeDO t3 = vo.getLevelThreeTypeName()!=null ? cityComponentTypeMapper.selectByNameAndParentAndLevel(vo.getLevelThreeTypeName(), t2!=null?t2.getTypeCode():null, 3) : null; + CityComponentSaveReqVO req = new CityComponentSaveReqVO(); + req.setComponentCode(vo.getComponentCode()); + if (t1 != null) req.setLevelOneTypeCode(t1.getTypeCode()); + if (t2 != null) req.setLevelTwoTypeCode(t2.getTypeCode()); + if (t3 != null) req.setLevelThreeTypeCode(t3.getTypeCode()); + req.setRoadName(vo.getRoadName()); req.setArea(vo.getArea()); + req.setCityCode("110"); req.setDistrictCode("102"); req.setStreetCode("001"); + req.setCoordx(vo.getCoordx()); req.setCoordy(vo.getCoordy()); req.setCoordz(vo.getCoordz()); + req.setInstallOrientation(vo.getInstallOrientation()); req.setGrid(vo.getGrid()); + req.setBrand(vo.getBrand()); req.setModelSpec(vo.getModelSpec()); req.setMaterial(vo.getMaterial()); + try { if (vo.getLength() != null && !vo.getLength().isEmpty()) req.setLength(new BigDecimal(vo.getLength())); } catch(Exception e){ } + try { if (vo.getWidth() != null && !vo.getWidth().isEmpty()) req.setWidth(new BigDecimal(vo.getWidth())); } catch(Exception e){ } + try { if (vo.getHeight() != null && !vo.getHeight().isEmpty()) req.setHeight(new BigDecimal(vo.getHeight())); } catch(Exception e){ } + try { if (vo.getDbh() != null && !vo.getDbh().isEmpty()) req.setDbh(new BigDecimal(vo.getDbh())); } catch(Exception e){ } + try { if (vo.getInstallDate() != null && !vo.getInstallDate().isEmpty()) req.setInstallDate(LocalDate.parse(vo.getInstallDate())); } catch(Exception e){ } + req.setAssetStatus(vo.getAssetStatus()); req.setManagementUnit(vo.getManagementUnit()); + req.setResponsiblePerson(vo.getResponsiblePerson()); + try { if (vo.getServiceYears() != null && !vo.getServiceYears().isEmpty()) req.setServiceYears(new BigDecimal(vo.getServiceYears())); } catch(Exception e){ } + try { if (vo.getMaintenanceDeadline() != null && !vo.getMaintenanceDeadline().isEmpty()) req.setMaintenanceDeadline(LocalDate.parse(vo.getMaintenanceDeadline())); } catch(Exception e){ } + req.setProcurementBatch(vo.getProcurementBatch()); req.setRemark(vo.getRemark()); + cityComponentService.create(req); + count++; + } + return success("成功导入 " + count + " 条记录"); + } +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentExportVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentExportVO.java new file mode 100644 index 0000000..f0e7bee --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentExportVO.java @@ -0,0 +1,67 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Schema(description = "城市部件导出 VO") +@Data +@ExcelIgnoreUnannotated +public class CityComponentExportVO { + + @ExcelProperty("资产ID") + private String componentCode; + @ExcelProperty("一级类型") + private String levelOneTypeName; + @ExcelProperty("二级类型") + private String levelTwoTypeName; + @ExcelProperty("三级类型") + private String levelThreeTypeName; + @ExcelProperty("所属区域") + private String area; + @ExcelProperty("道路名称") + private String roadName; + @ExcelProperty("安装方位") + private String installOrientation; + @ExcelProperty("所属网格") + private String grid; + @ExcelProperty("品牌") + private String brand; + @ExcelProperty("型号规格") + private String modelSpec; + @ExcelProperty("材质") + private String material; + @ExcelProperty("安装时间") + private LocalDate installDate; + @ExcelProperty("资产状态") + private String assetStatus; + @ExcelProperty("管理单位") + private String managementUnit; + @ExcelProperty("责任人") + private String responsiblePerson; + @ExcelProperty("维保到期日") + private LocalDate maintenanceDeadline; + @ExcelProperty("巡检周期") + private String inspectionCycle; + @ExcelProperty("最近巡检时间") + private LocalDateTime lastInspectionTime; + @ExcelProperty("巡检结果") + private String inspectionResult; + @ExcelProperty("异常描述") + private String abnormalDescription; + @ExcelProperty("报修工单编号") + private String repairOrderNo; + @ExcelProperty("维修完成时间") + private LocalDateTime repairCompleteTime; + @ExcelProperty("维修单位") + private String repairUnit; + @ExcelProperty("图片信息") + private String imageUrls; + @ExcelProperty("备注") + private String remark; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentImportVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentImportVO.java new file mode 100644 index 0000000..b0344bb --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentImportVO.java @@ -0,0 +1,77 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo; + +import cn.idev.excel.annotation.ExcelProperty; +import lombok.Data; + +@Data +public class CityComponentImportVO { + + @ExcelProperty(index = 0) + private String levelOneTypeName; // 一级资产类型 + @ExcelProperty(index = 1) + private String levelTwoTypeName; // 二级资产类型 + @ExcelProperty(index = 2) + private String levelThreeTypeName; // 三级资产类型 + @ExcelProperty(index = 3) + private String componentCode; // 资产ID + @ExcelProperty(index = 4) + private String area; // 所属区域 + @ExcelProperty(index = 5) + private String coordx; // X坐标 + @ExcelProperty(index = 6) + private String coordy; // Y坐标 + @ExcelProperty(index = 7) + private String coordz; // Z坐标 + @ExcelProperty(index = 8) + private String roadName; // 道路名称 + @ExcelProperty(index = 9) + private String installOrientation; // 安装方位 + @ExcelProperty(index = 10) + private String grid; // 所属网格 + @ExcelProperty(index = 11) + private String brand; // 品牌/厂家 + @ExcelProperty(index = 12) + private String modelSpec; // 型号规格 + @ExcelProperty(index = 13) + private String material; // 材质 + @ExcelProperty(index = 14) + private String length; // 长 + @ExcelProperty(index = 15) + private String width; // 宽 + @ExcelProperty(index = 16) + private String height; // 高 + @ExcelProperty(index = 17) + private String dbh; // 胸径 + @ExcelProperty(index = 18) + private String installDate; // 安装时间/种植时间 + @ExcelProperty(index = 19) + private String assetStatus; // 资产状态 + @ExcelProperty(index = 20) + private String managementUnit; // 管理单位 + @ExcelProperty(index = 21) + private String responsiblePerson; // 责任人 + @ExcelProperty(index = 22) + private String serviceYears; // 投入年限 + @ExcelProperty(index = 23) + private String maintenanceDeadline; // 维保到期日 + @ExcelProperty(index = 24) + private String procurementBatch; // 采购批次/项目名称 + @ExcelProperty(index = 25) + private String inspectionCycle; // 巡检周期 + @ExcelProperty(index = 26) + private String lastInspectionTime; // 最近巡检时间 + @ExcelProperty(index = 27) + private String inspector; // 巡检人员 + @ExcelProperty(index = 28) + private String inspectionResult; // 巡检结果 + @ExcelProperty(index = 29) + private String abnormalDescription; // 异常描述 + @ExcelProperty(index = 30) + private String repairOrderNo; // 报修工单编号 + @ExcelProperty(index = 31) + private String repairCompleteTime; // 维修完成时间 + @ExcelProperty(index = 32) + private String repairUnit; // 维修单位 + @ExcelProperty(index = 33) + private String remark; // 备注 +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentPageReqVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentPageReqVO.java new file mode 100644 index 0000000..2f9d2f0 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentPageReqVO.java @@ -0,0 +1,29 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.zteits.urbanops.framework.common.pojo.PageParam; +import java.time.LocalDate; + +@Schema(description = "城市部件分页查询 Request VO") +@Data +public class CityComponentPageReqVO extends PageParam { + + private String componentCode; + private String levelOneTypeCode; + private String levelTwoTypeCode; + private String levelThreeTypeCode; + private String streetCode; + private String area; + private String roadName; + private String installOrientation; + private String grid; + private String assetStatus; + private String managementUnit; + private String brand; + private String material; + private String responsiblePerson; + private String procurementBatch; + private LocalDate installDate; + private LocalDate maintenanceDeadline; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentRespVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentRespVO.java new file mode 100644 index 0000000..fabf14c --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentRespVO.java @@ -0,0 +1,103 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import cn.idev.excel.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.zteits.urbanops.module.garden.util.TwoDecimalFloatSerializer; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Schema(description = "城市部件 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CityComponentRespVO { + + private Long id; + + @ExcelProperty("资产ID") + private String componentCode; + + @ExcelProperty("一级类型") + private String levelOneTypeName; + @ExcelProperty("二级类型") + private String levelTwoTypeName; + @ExcelProperty("三级类型") + private String levelThreeTypeName; + + private String levelOneTypeCode; + private String levelTwoTypeCode; + private String levelThreeTypeCode; + + private String cityCode; + private String districtCode; + private String streetCode; + + @ExcelProperty("所属区域") + private String area; + + @ExcelProperty("道路名称") + private String roadName; + private String roadCode; + + @ExcelProperty("X坐标") + private BigDecimal xCoord; + @ExcelProperty("Y坐标") + private BigDecimal yCoord; + + private BigDecimal zCoord; + private BigDecimal longitudeAmap; + private BigDecimal latitudeAmap; + + @ExcelProperty("安装方位") + private String installOrientation; + @ExcelProperty("所属网格") + private String grid; + + @ExcelProperty("品牌") + private String brand; + @ExcelProperty("型号规格") + private String modelSpec; + @ExcelProperty("材质") + private String material; + + private BigDecimal length; + private BigDecimal width; + private BigDecimal height; + private BigDecimal dbh; + + @ExcelProperty("安装时间") + private LocalDate installDate; + @ExcelProperty("资产状态") + private String assetStatus; + @ExcelProperty("管理单位") + private String managementUnit; + @ExcelProperty("责任人") + private String responsiblePerson; + + private BigDecimal serviceYears; + private LocalDate maintenanceDeadline; + private String procurementBatch; + + private String inspectionCycle; + private LocalDateTime lastInspectionTime; + private String inspector; + @ExcelProperty("巡检结果") + private String inspectionResult; + private String abnormalDescription; + + private String repairOrderNo; + private LocalDateTime repairCompleteTime; + private String repairUnit; + + @ExcelProperty("备注") + private String remark; + + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + private String imageUrls; + private String qrCodeUrl; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentSaveReqVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentSaveReqVO.java new file mode 100644 index 0000000..bc8387b --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponent/vo/CityComponentSaveReqVO.java @@ -0,0 +1,66 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import jakarta.validation.constraints.NotEmpty; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Schema(description = "城市部件新增/修改 Request VO") +@Data +public class CityComponentSaveReqVO { + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "资产ID(一物一码)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "资产ID不能为空") + private String componentCode; + + private String levelOneTypeCode; + private String levelTwoTypeCode; + private String levelThreeTypeCode; + + private String cityCode; + private String districtCode; + private String streetCode; + + private String area; + private String roadCode; + private String roadName; + private String coordx; + private String coordy; + private String coordz; + private String installOrientation; + private String grid; + + private String brand; + private String modelSpec; + private String material; + private BigDecimal length; + private BigDecimal width; + private BigDecimal height; + private BigDecimal dbh; + + private LocalDate installDate; + private String assetStatus; + private String managementUnit; + private String responsiblePerson; + private BigDecimal serviceYears; + private LocalDate maintenanceDeadline; + private String procurementBatch; + + private String inspectionCycle; + private LocalDateTime lastInspectionTime; + private String inspector; + private String inspectionResult; + private String abnormalDescription; + + private String repairOrderNo; + private LocalDateTime repairCompleteTime; + private String repairUnit; + + private String remark; + private String imageUrls; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/CityComponentTypeController.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/CityComponentTypeController.java new file mode 100644 index 0000000..32388ad --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/CityComponentTypeController.java @@ -0,0 +1,142 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponenttype; + +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypePageReqVO; +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypeRespVO; +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypeSaveReqVO; +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.*; + +import java.util.*; + +import com.zteits.urbanops.framework.common.pojo.CommonResult; +import com.zteits.urbanops.framework.common.pojo.PageResult; +import com.zteits.urbanops.framework.common.util.object.BeanUtils; +import static com.zteits.urbanops.framework.common.pojo.CommonResult.success; + +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponenttype.CityComponentTypeDO; +import com.zteits.urbanops.module.garden.dal.mysql.citycomponenttype.CityComponentTypeMapper; +import com.zteits.urbanops.module.garden.service.citycomponenttype.CityComponentTypeService; + +@Tag(name = "管理后台 - 城市部件类型") +@RestController +@RequestMapping("/garden/city-component-type") +@Validated +public class CityComponentTypeController { + + @Resource + private CityComponentTypeService cityComponentTypeService; + + @Resource + private CityComponentTypeMapper cityComponentTypeMapper; + + @PostMapping("/create") + @Operation(summary = "新增城市部件类型") + @PreAuthorize("@ss.hasPermission('garden:city-component-type:create')") + public CommonResult createType(@Valid @RequestBody CityComponentTypeSaveReqVO createReqVO) { + return success(cityComponentTypeService.createType(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改城市部件类型") + @PreAuthorize("@ss.hasPermission('garden:city-component-type:update')") + public CommonResult updateType(@Valid @RequestBody CityComponentTypeSaveReqVO updateReqVO) { + cityComponentTypeService.updateType(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除城市部件类型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('garden:city-component-type:delete')") + public CommonResult deleteType(@RequestParam("id") Long id) { + cityComponentTypeService.deleteType(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得城市部件类型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('garden:city-component-type:query')") + public CommonResult getType(@RequestParam("id") Long id) { + CityComponentTypeDO type = cityComponentTypeService.getType(id); + CityComponentTypeRespVO respVO = BeanUtils.toBean(type, CityComponentTypeRespVO.class); + fillParentNames(Arrays.asList(respVO)); + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得城市部件类型分页") + @PreAuthorize("@ss.hasPermission('garden:city-component-type:query')") + public CommonResult> getTypePage(@Valid CityComponentTypePageReqVO pageReqVO) { + PageResult pageResult = cityComponentTypeService.getTypePage(pageReqVO); + PageResult voPageResult = BeanUtils.toBean(pageResult, CityComponentTypeRespVO.class); + fillParentNames(voPageResult.getList()); + return success(voPageResult); + } + + @GetMapping("/list-by-parent") + @Operation(summary = "根据父级编码查询子类型(级联下拉用)") + @PreAuthorize("@ss.hasPermission('garden:city-component-type:query')") + public CommonResult> listByParent( + @RequestParam(value = "parentCode", required = false) String parentCode, + @RequestParam("level") Integer level) { + return success(BeanUtils.toBean( + cityComponentTypeService.getTypeByParentCode(parentCode, level), + CityComponentTypeRespVO.class)); + } + + @GetMapping("/generate-next-code") + @Operation(summary = "生成下一级类型编码") + @PreAuthorize("@ss.hasPermission('garden:city-component-type:create')") + public CommonResult generateNextCode(@RequestParam("parentCode") String parentCode) { + return success(cityComponentTypeService.generateNextCode(parentCode)); + } + + @PostMapping("/sync-level-one") + @Operation(summary = "同步一级类型") + @PreAuthorize("@ss.hasPermission('garden:city-component-type:create')") + public CommonResult syncLevelOne() { return success(cityComponentTypeService.syncLevelOne()); } + + @GetMapping("/tree") + @Operation(summary = "获取完整类型树") + @PreAuthorize("@ss.hasPermission('garden:city-component-type:query')") + public CommonResult> getTree() { + List list = cityComponentTypeService.getTree(); + List result = BeanUtils.toBean(list, CityComponentTypeRespVO.class); + fillParentNames(result); + return success(result); + } + + private void fillParentNames(List list) { + if (list == null || list.isEmpty()) return; + for (CityComponentTypeRespVO vo : list) { + if (vo.getLevel() == null) continue; + if (vo.getLevel() == 1) { + vo.setLevelOneName(vo.getTypeName()); + } else if (vo.getLevel() == 2) { + vo.setLevelTwoName(vo.getTypeName()); + if (vo.getParentCode() != null) { + CityComponentTypeDO parent = cityComponentTypeMapper.selectByTypeCode(vo.getParentCode()); + if (parent != null) vo.setLevelOneName(parent.getTypeName()); + } + } else if (vo.getLevel() == 3) { + if (vo.getParentCode() != null) { + CityComponentTypeDO parent = cityComponentTypeMapper.selectByTypeCode(vo.getParentCode()); + if (parent != null) { + vo.setLevelTwoName(parent.getTypeName()); + if (parent.getParentCode() != null) { + CityComponentTypeDO gp = cityComponentTypeMapper.selectByTypeCode(parent.getParentCode()); + if (gp != null) vo.setLevelOneName(gp.getTypeName()); + } + } + } + } + } + } +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypePageReqVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypePageReqVO.java new file mode 100644 index 0000000..efb5872 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypePageReqVO.java @@ -0,0 +1,28 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.zteits.urbanops.framework.common.pojo.PageParam; + +@Schema(description = "管理后台 - 城市部件类型分页 Request VO") +@Data +public class CityComponentTypePageReqVO extends PageParam { + + @Schema(description = "类型编码") + private String typeCode; + + @Schema(description = "类型名称") + private String typeName; + + @Schema(description = "层级:1=一级 2=二级 3=三级") + private Integer level; + + @Schema(description = "父级类型编码") + private String parentCode; + + @Schema(description = "一级类型编码(级联筛选)") + private String levelOneCode; + + @Schema(description = "状态:1启用 0禁用") + private Integer status; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeRespVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeRespVO.java new file mode 100644 index 0000000..8826a6e --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeRespVO.java @@ -0,0 +1,57 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 城市部件类型 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CityComponentTypeRespVO { + + @Schema(description = "主键ID") + @ExcelProperty("主键ID") + private Long id; + + @Schema(description = "类型编码") + @ExcelProperty("类型编码") + private String typeCode; + + @Schema(description = "类型名称") + @ExcelProperty("类型名称") + private String typeName; + + @Schema(description = "层级:1=一级 2=二级 3=三级") + @ExcelProperty("层级") + private Integer level; + + @Schema(description = "父级类型编码") + @ExcelProperty("父级类型编码") + private String parentCode; + + @Schema(description = "排序序号") + @ExcelProperty("排序序号") + private Integer sort; + + @Schema(description = "状态:1启用 0禁用") + @ExcelProperty("状态") + private Integer status; + + @Schema(description = "备注") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "一级类型名称(计算字段)") + private String levelOneName; + + @Schema(description = "二级类型名称(计算字段)") + private String levelTwoName; + + @Schema(description = "创建者") + @ExcelProperty("创建者") + private String creator; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private String createTime; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeSaveReqVO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeSaveReqVO.java new file mode 100644 index 0000000..4537718 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/citycomponenttype/vo/CityComponentTypeSaveReqVO.java @@ -0,0 +1,38 @@ +package com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - 城市部件类型新增/修改 Request VO") +@Data +public class CityComponentTypeSaveReqVO { + + @Schema(description = "主键ID", example = "1") + private Long id; + + @Schema(description = "类型编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "021") + @NotEmpty(message = "类型编码不能为空") + private String typeCode; + + @Schema(description = "类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "照明灯") + @NotEmpty(message = "类型名称不能为空") + private String typeName; + + @Schema(description = "层级:1=一级 2=二级 3=三级", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "层级不能为空") + private Integer level; + + @Schema(description = "父级类型编码", example = "02") + private String parentCode; + + @Schema(description = "排序序号", example = "1") + private Integer sort; + + @Schema(description = "状态:1启用 0禁用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "备注") + private String remark; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponent/CityComponentDO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponent/CityComponentDO.java new file mode 100644 index 0000000..7d3ba08 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponent/CityComponentDO.java @@ -0,0 +1,77 @@ +package com.zteits.urbanops.module.garden.dal.dataobject.citycomponent; + +import lombok.*; +import com.baomidou.mybatisplus.annotation.*; +import com.zteits.urbanops.framework.mybatis.core.dataobject.BaseDO; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@TableName("garden_city_component") +@KeySequence("garden_city_component_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CityComponentDO extends BaseDO { + + @TableId + private Long id; + + private String componentCode; + + private String levelOneTypeCode; + private String levelOneTypeName; + private String levelTwoTypeCode; + private String levelTwoTypeName; + private String levelThreeTypeCode; + private String levelThreeTypeName; + + private String cityCode; + private String districtCode; + private String streetCode; + + private String area; + private String roadCode; + private String roadName; + private BigDecimal xCoord; + private BigDecimal yCoord; + private BigDecimal zCoord; + private BigDecimal longitudeAmap; + private BigDecimal latitudeAmap; + private String installOrientation; + private String grid; + + private String brand; + private String modelSpec; + private String material; + private BigDecimal length; + private BigDecimal width; + private BigDecimal height; + private BigDecimal dbh; + + private LocalDate installDate; + private String assetStatus; + private String managementUnit; + private String responsiblePerson; + private BigDecimal serviceYears; + private LocalDate maintenanceDeadline; + private String procurementBatch; + + private String inspectionCycle; + private LocalDateTime lastInspectionTime; + private String inspector; + private String inspectionResult; + private String abnormalDescription; + + private String repairOrderNo; + private LocalDateTime repairCompleteTime; + private String repairUnit; + + private String remark; + private String qrCodeUrl; + private String imageUrls; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponenttype/CityComponentTypeDO.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponenttype/CityComponentTypeDO.java new file mode 100644 index 0000000..b4b0e4c --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/citycomponenttype/CityComponentTypeDO.java @@ -0,0 +1,30 @@ +package com.zteits.urbanops.module.garden.dal.dataobject.citycomponenttype; + +import lombok.*; +import com.baomidou.mybatisplus.annotation.*; +import com.zteits.urbanops.framework.mybatis.core.dataobject.BaseDO; + +/** + * 城市部件类型三级分类 DO + */ +@TableName("garden_city_component_type") +@KeySequence("garden_city_component_type_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CityComponentTypeDO extends BaseDO { + + @TableId + private Long id; + + private String typeCode; + private String typeName; + private Integer level; + private String parentCode; + private Integer sort; + private Integer status; + private String remark; +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponent/CityComponentMapper.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponent/CityComponentMapper.java new file mode 100644 index 0000000..3f52ebf --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponent/CityComponentMapper.java @@ -0,0 +1,40 @@ +package com.zteits.urbanops.module.garden.dal.mysql.citycomponent; + +import com.zteits.urbanops.framework.common.pojo.PageResult; +import com.zteits.urbanops.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.zteits.urbanops.framework.mybatis.core.mapper.BaseMapperX; +import com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo.CityComponentPageReqVO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponent.CityComponentDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CityComponentMapper extends BaseMapperX { + + default PageResult selectPage(CityComponentPageReqVO reqVO) { + LambdaQueryWrapperX wrapper = new LambdaQueryWrapperX() + .eqIfPresent(CityComponentDO::getComponentCode, reqVO.getComponentCode()) + .eqIfPresent(CityComponentDO::getLevelOneTypeCode, reqVO.getLevelOneTypeCode()) + .eqIfPresent(CityComponentDO::getLevelTwoTypeCode, reqVO.getLevelTwoTypeCode()) + .eqIfPresent(CityComponentDO::getLevelThreeTypeCode, reqVO.getLevelThreeTypeCode()) + .eqIfPresent(CityComponentDO::getStreetCode, reqVO.getStreetCode()) + .likeIfPresent(CityComponentDO::getArea, reqVO.getArea()) + .likeIfPresent(CityComponentDO::getRoadName, reqVO.getRoadName()) + .eqIfPresent(CityComponentDO::getInstallOrientation, reqVO.getInstallOrientation()) + .likeIfPresent(CityComponentDO::getGrid, reqVO.getGrid()) + .eqIfPresent(CityComponentDO::getAssetStatus, reqVO.getAssetStatus()) + .likeIfPresent(CityComponentDO::getManagementUnit, reqVO.getManagementUnit()) + .likeIfPresent(CityComponentDO::getBrand, reqVO.getBrand()) + .likeIfPresent(CityComponentDO::getMaterial, reqVO.getMaterial()) + .likeIfPresent(CityComponentDO::getResponsiblePerson, reqVO.getResponsiblePerson()) + .likeIfPresent(CityComponentDO::getProcurementBatch, reqVO.getProcurementBatch()) + .eqIfPresent(CityComponentDO::getInstallDate, reqVO.getInstallDate()) + .eqIfPresent(CityComponentDO::getMaintenanceDeadline, reqVO.getMaintenanceDeadline()); + wrapper.orderByDesc(CityComponentDO::getId); + return selectPage(reqVO, wrapper); + } + + default CityComponentDO selectByComponentCode(String componentCode) { + return selectOne(new LambdaQueryWrapperX() + .eq(CityComponentDO::getComponentCode, componentCode)); + } +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponenttype/CityComponentTypeMapper.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponenttype/CityComponentTypeMapper.java new file mode 100644 index 0000000..51c85b5 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/citycomponenttype/CityComponentTypeMapper.java @@ -0,0 +1,96 @@ +package com.zteits.urbanops.module.garden.dal.mysql.citycomponenttype; + +import com.zteits.urbanops.framework.common.pojo.PageResult; +import com.zteits.urbanops.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.zteits.urbanops.framework.mybatis.core.mapper.BaseMapperX; +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypePageReqVO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponenttype.CityComponentTypeDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Mapper +public interface CityComponentTypeMapper extends BaseMapperX { + + default PageResult selectPage(CityComponentTypePageReqVO reqVO) { + LambdaQueryWrapperX wrapper = new LambdaQueryWrapperX() + .eqIfPresent(CityComponentTypeDO::getLevel, reqVO.getLevel()) + .eqIfPresent(CityComponentTypeDO::getStatus, reqVO.getStatus()) + .likeIfPresent(CityComponentTypeDO::getTypeName, reqVO.getTypeName()) + .eqIfPresent(CityComponentTypeDO::getTypeCode, reqVO.getTypeCode()); + wrapper.orderByAsc(CityComponentTypeDO::getSort); + wrapper.orderByAsc(CityComponentTypeDO::getId); + + if (reqVO.getLevelOneCode() != null && !reqVO.getLevelOneCode().isEmpty()) { + List levelTwoList = selectByParentCodeAndLevel(reqVO.getLevelOneCode(), 2); + List parentCodes = new ArrayList<>(); + parentCodes.add(reqVO.getLevelOneCode()); + parentCodes.addAll(levelTwoList.stream().map(CityComponentTypeDO::getTypeCode).collect(Collectors.toList())); + wrapper.in(CityComponentTypeDO::getParentCode, parentCodes); + } else { + wrapper.eqIfPresent(CityComponentTypeDO::getParentCode, reqVO.getParentCode()); + } + return selectPage(reqVO, wrapper); + } + + default List selectByParentCodeAndLevel(String parentCode, Integer level) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(CityComponentTypeDO::getParentCode, parentCode) + .eqIfPresent(CityComponentTypeDO::getLevel, level) + .eq(CityComponentTypeDO::getStatus, 1) + .orderByAsc(CityComponentTypeDO::getSort) + .orderByAsc(CityComponentTypeDO::getId)); + } + + default CityComponentTypeDO selectByTypeCode(String typeCode) { + return selectOne(new LambdaQueryWrapperX() + .eq(CityComponentTypeDO::getTypeCode, typeCode)); + } + + default CityComponentTypeDO selectByNameAndParentAndLevel(String typeName, String parentCode, Integer level) { + return selectOne(new LambdaQueryWrapperX() + .eq(CityComponentTypeDO::getTypeName, typeName) + .eqIfPresent(CityComponentTypeDO::getParentCode, parentCode) + .eq(CityComponentTypeDO::getLevel, level) + .last("LIMIT 1")); + } + + @Select("SELECT COUNT(1) FROM garden_city_component_type WHERE type_code = #{code}") + int countByTypeCodeRaw(@Param("code") String code); + + /** + * 生成下一级编码:父级编码 + 递增序号 + * 如 parentCode=02 → 下一个 max+1 → 02+1=021, 02+2=022 + */ + default String generateNextCode(String parentCode) { + int childLen = parentCode.length() + 1; + List list = selectList(new LambdaQueryWrapperX() + .likeRight(CityComponentTypeDO::getTypeCode, parentCode) + .apply("LENGTH(type_code) = {0}", childLen) + .orderByDesc(CityComponentTypeDO::getTypeCode) + .last("LIMIT 1")); + int seq; + if (list == null || list.isEmpty()) { + seq = 1; + } else { + String maxCode = list.get(0).getTypeCode(); + String seqStr = maxCode.substring(parentCode.length()); + try { + seq = Integer.parseInt(seqStr) + 1; + } catch (NumberFormatException e) { + seq = 1; + } + } + int maxAttempts = 100; + String nextCode; + do { + nextCode = parentCode + seq; + seq++; + } while (countByTypeCodeRaw(nextCode) > 0 && --maxAttempts > 0); + return nextCode; + } +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/ErrorCodeConstants.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/ErrorCodeConstants.java index e6f1419..956cb7e 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/ErrorCodeConstants.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/ErrorCodeConstants.java @@ -155,6 +155,16 @@ public interface ErrorCodeConstants { // ========== 一树一档案巡检与风险评估 1-100-008-000 ========== ErrorCode TREE_INSPECTION_NOT_EXISTS = new ErrorCode(1100008001, "巡检评估记录不存在"); + // ========== 城市部件类型 1-100-015-000 ========== + ErrorCode CITY_COMPONENT_TYPE_NOT_EXISTS = new ErrorCode(1-100-015-001, "城市部件类型不存在"); + ErrorCode CITY_COMPONENT_TYPE_CODE_EXISTS = new ErrorCode(1-100-015-002, "城市部件类型编码已存在"); + ErrorCode CITY_COMPONENT_TYPE_NAME_EXISTS = new ErrorCode(1-100-015-003, "同级下类型名称已存在"); + ErrorCode CITY_COMPONENT_TYPE_HAS_CHILDREN = new ErrorCode(1-100-015-004, "该类型下存在子级类型,无法删除。请先删除子级类型"); + + // ========== 城市部件管理 1-100-016-000 ========== + ErrorCode CITY_COMPONENT_NOT_EXISTS = new ErrorCode(1-100-016-001, "城市部件不存在"); + ErrorCode CITY_COMPONENT_CODE_EXISTS = new ErrorCode(1-100-016-002, "资产ID编码已存在"); + //文件异步下载 ErrorCode FILE_DOWNLOAD_NOT_EXISTS = new ErrorCode(1-100-000-001, "文件异步下载任务不存在"); diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentService.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentService.java new file mode 100644 index 0000000..feb9edc --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentService.java @@ -0,0 +1,26 @@ +package com.zteits.urbanops.module.garden.service.citycomponent; + +import com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo.CityComponentPageReqVO; +import com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo.CityComponentSaveReqVO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponent.CityComponentDO; +import com.zteits.urbanops.framework.common.pojo.PageResult; +import jakarta.validation.Valid; + +import java.util.List; + +public interface CityComponentService { + + Long create(@Valid CityComponentSaveReqVO reqVO); + + void update(@Valid CityComponentSaveReqVO reqVO); + + void delete(Long id); + + CityComponentDO get(Long id); + + PageResult getPage(CityComponentPageReqVO reqVO); + + List getList(CityComponentPageReqVO reqVO); + + String generateQrCode(Long id); +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentServiceImpl.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentServiceImpl.java new file mode 100644 index 0000000..24fdb8a --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponent/CityComponentServiceImpl.java @@ -0,0 +1,136 @@ +package com.zteits.urbanops.module.garden.service.citycomponent; + +import com.zteits.urbanops.framework.common.pojo.PageResult; +import com.zteits.urbanops.framework.common.util.object.BeanUtils; +import com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil; +import com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo.CityComponentPageReqVO; +import com.zteits.urbanops.module.garden.controller.admin.citycomponent.vo.CityComponentSaveReqVO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponent.CityComponentDO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponenttype.CityComponentTypeDO; +import com.zteits.urbanops.module.garden.dal.mysql.citycomponent.CityComponentMapper; +import com.zteits.urbanops.module.garden.dal.mysql.citycomponenttype.CityComponentTypeMapper; +import com.zteits.urbanops.module.garden.enums.ErrorCodeConstants; +import com.zteits.urbanops.module.garden.util.GisCoordinateUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Objects; + +@Service +public class CityComponentServiceImpl implements CityComponentService { + + @Resource + private CityComponentMapper cityComponentMapper; + + @Resource + private CityComponentTypeMapper cityComponentTypeMapper; + + @Override + @Transactional + public Long create(@Valid CityComponentSaveReqVO reqVO) { + validateCodeUnique(reqVO.getComponentCode(), null); + CityComponentDO comp = BeanUtils.toBean(reqVO, CityComponentDO.class); + if (reqVO.getCoordx() != null) comp.setXCoord(new BigDecimal(reqVO.getCoordx())); + if (reqVO.getCoordy() != null) comp.setYCoord(new BigDecimal(reqVO.getCoordy())); + if (reqVO.getCoordz() != null) comp.setZCoord(new BigDecimal(reqVO.getCoordz())); + fillTypeNames(comp); + convertCoordinates(comp); + cityComponentMapper.insert(comp); + return comp.getId(); + } + + @Override + @Transactional + public void update(@Valid CityComponentSaveReqVO reqVO) { + if (reqVO.getId() == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_NOT_EXISTS); + } + CityComponentDO exist = cityComponentMapper.selectById(reqVO.getId()); + if (exist == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_NOT_EXISTS); + } + validateCodeUnique(reqVO.getComponentCode(), reqVO.getId()); + CityComponentDO comp = BeanUtils.toBean(reqVO, CityComponentDO.class); + if (reqVO.getCoordx() != null) comp.setXCoord(new BigDecimal(reqVO.getCoordx())); + if (reqVO.getCoordy() != null) comp.setYCoord(new BigDecimal(reqVO.getCoordy())); + if (reqVO.getCoordz() != null) comp.setZCoord(new BigDecimal(reqVO.getCoordz())); + fillTypeNames(comp); + convertCoordinates(comp); + cityComponentMapper.updateById(comp); + } + + @Override + @Transactional + public void delete(Long id) { + CityComponentDO exist = cityComponentMapper.selectById(id); + if (exist == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_NOT_EXISTS); + } + cityComponentMapper.deleteById(id); + } + + @Override + public CityComponentDO get(Long id) { + CityComponentDO comp = cityComponentMapper.selectById(id); + if (comp == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_NOT_EXISTS); + } + return comp; + } + + @Override + public PageResult getPage(CityComponentPageReqVO reqVO) { + return cityComponentMapper.selectPage(reqVO); + } + + @Override + public List getList(CityComponentPageReqVO reqVO) { + return cityComponentMapper.selectList(); + } + + @Override + public String generateQrCode(Long id) { + CityComponentDO comp = get(id); + String url = "https://urbanops.zteits.com/component/" + comp.getComponentCode(); + comp.setQrCodeUrl(url); + cityComponentMapper.updateById(comp); + return url; + } + + private void validateCodeUnique(String code, Long excludeId) { + if (code == null || code.isEmpty()) return; + CityComponentDO exist = cityComponentMapper.selectByComponentCode(code); + if (exist != null && !Objects.equals(exist.getId(), excludeId)) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_CODE_EXISTS); + } + } + + private void fillTypeNames(CityComponentDO comp) { + if (comp.getLevelOneTypeCode() != null) { + CityComponentTypeDO t = cityComponentTypeMapper.selectByTypeCode(comp.getLevelOneTypeCode()); + if (t != null) comp.setLevelOneTypeName(t.getTypeName()); + } + if (comp.getLevelTwoTypeCode() != null) { + CityComponentTypeDO t = cityComponentTypeMapper.selectByTypeCode(comp.getLevelTwoTypeCode()); + if (t != null) comp.setLevelTwoTypeName(t.getTypeName()); + } + if (comp.getLevelThreeTypeCode() != null) { + CityComponentTypeDO t = cityComponentTypeMapper.selectByTypeCode(comp.getLevelThreeTypeCode()); + if (t != null) comp.setLevelThreeTypeName(t.getTypeName()); + } + } + + private void convertCoordinates(CityComponentDO comp) { + if (comp.getXCoord() != null && comp.getYCoord() != null) { + double[] gcj02 = GisCoordinateUtil.wgs84ToGcj02( + comp.getXCoord().doubleValue(), + comp.getYCoord().doubleValue()); + comp.setLongitudeAmap(BigDecimal.valueOf(gcj02[0])); + comp.setLatitudeAmap(BigDecimal.valueOf(gcj02[1])); + } + } +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeService.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeService.java new file mode 100644 index 0000000..876234d --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeService.java @@ -0,0 +1,30 @@ +package com.zteits.urbanops.module.garden.service.citycomponenttype; + +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypePageReqVO; +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypeSaveReqVO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponenttype.CityComponentTypeDO; +import com.zteits.urbanops.framework.common.pojo.PageResult; +import jakarta.validation.Valid; + +import java.util.List; + +public interface CityComponentTypeService { + + Long createType(@Valid CityComponentTypeSaveReqVO createReqVO); + + void updateType(@Valid CityComponentTypeSaveReqVO updateReqVO); + + void deleteType(Long id); + + CityComponentTypeDO getType(Long id); + + PageResult getTypePage(CityComponentTypePageReqVO pageReqVO); + + List getTypeByParentCode(String parentCode, Integer level); + + String generateNextCode(String parentCode); + + /** 获取完整类型树 */ + List getTree(); + int syncLevelOne(); +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeServiceImpl.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeServiceImpl.java new file mode 100644 index 0000000..f7e1830 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/citycomponenttype/CityComponentTypeServiceImpl.java @@ -0,0 +1,127 @@ +package com.zteits.urbanops.module.garden.service.citycomponenttype; + +import com.zteits.urbanops.framework.common.pojo.PageResult; +import com.zteits.urbanops.framework.common.util.object.BeanUtils; +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypePageReqVO; +import com.zteits.urbanops.module.garden.controller.admin.citycomponenttype.vo.CityComponentTypeSaveReqVO; +import com.zteits.urbanops.module.garden.dal.dataobject.citycomponenttype.CityComponentTypeDO; +import com.zteits.urbanops.module.garden.dal.mysql.citycomponenttype.CityComponentTypeMapper; +import com.zteits.urbanops.module.garden.enums.ErrorCodeConstants; +import com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import java.util.List; +import java.util.Objects; + +@Service +public class CityComponentTypeServiceImpl implements CityComponentTypeService { + + @Resource + private CityComponentTypeMapper cityComponentTypeMapper; + + @Override + @Transactional + public Long createType(@Valid CityComponentTypeSaveReqVO createReqVO) { + validateTypeCodeUnique(createReqVO.getTypeCode(), null); + validateTypeNameUnique(createReqVO.getTypeName(), createReqVO.getParentCode(), + createReqVO.getLevel(), null); + CityComponentTypeDO type = BeanUtils.toBean(createReqVO, CityComponentTypeDO.class); + cityComponentTypeMapper.insert(type); + return type.getId(); + } + + @Override + @Transactional + public void updateType(@Valid CityComponentTypeSaveReqVO updateReqVO) { + if (updateReqVO.getId() == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_TYPE_NOT_EXISTS); + } + CityComponentTypeDO exist = cityComponentTypeMapper.selectById(updateReqVO.getId()); + if (exist == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_TYPE_NOT_EXISTS); + } + validateTypeCodeUnique(updateReqVO.getTypeCode(), updateReqVO.getId()); + validateTypeNameUnique(updateReqVO.getTypeName(), updateReqVO.getParentCode(), + updateReqVO.getLevel(), updateReqVO.getId()); + CityComponentTypeDO type = BeanUtils.toBean(updateReqVO, CityComponentTypeDO.class); + cityComponentTypeMapper.updateById(type); + } + + @Override + @Transactional + public void deleteType(Long id) { + CityComponentTypeDO exist = cityComponentTypeMapper.selectById(id); + if (exist == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_TYPE_NOT_EXISTS); + } + // 检查是否存在子级,存在则不允许删除 + String typeCode = exist.getTypeCode(); + if (exist.getLevel() <= 2) { + List children = cityComponentTypeMapper.selectByParentCodeAndLevel(typeCode, exist.getLevel() + 1); + if (children != null && !children.isEmpty()) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_TYPE_HAS_CHILDREN); + } + } + cityComponentTypeMapper.deleteById(id); + } + + @Override + public CityComponentTypeDO getType(Long id) { + CityComponentTypeDO type = cityComponentTypeMapper.selectById(id); + if (type == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_TYPE_NOT_EXISTS); + } + return type; + } + + @Override + public PageResult getTypePage(CityComponentTypePageReqVO pageReqVO) { + return cityComponentTypeMapper.selectPage(pageReqVO); + } + + @Override + public List getTypeByParentCode(String parentCode, Integer level) { + return cityComponentTypeMapper.selectByParentCodeAndLevel(parentCode, level); + } + + @Override + public String generateNextCode(String parentCode) { + return cityComponentTypeMapper.generateNextCode(parentCode); + } + + @Override + public List getTree() { + return cityComponentTypeMapper.selectList(); + } + + @Override + public int syncLevelOne() { + String[][] items = {{"01","建筑要素"},{"02","公共设施要素"},{"03","园林绿化要素"},{"04","道路交通要素"}}; + int cnt = 0; + for (String[] item : items) { + if (cityComponentTypeMapper.selectByTypeCode(item[0]) == null) { + CityComponentTypeDO t = CityComponentTypeDO.builder().typeCode(item[0]).typeName(item[1]) + .level(1).sort(cnt+1).status(1).build(); + cityComponentTypeMapper.insert(t); cnt++; + } + } + return cnt; + } + + private void validateTypeCodeUnique(String typeCode, Long excludeId) { + CityComponentTypeDO exist = cityComponentTypeMapper.selectByTypeCode(typeCode); + if (exist != null && !Objects.equals(exist.getId(), excludeId)) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_TYPE_CODE_EXISTS); + } + } + + private void validateTypeNameUnique(String typeName, String parentCode, Integer level, Long excludeId) { + CityComponentTypeDO exist = cityComponentTypeMapper.selectByNameAndParentAndLevel(typeName, parentCode, level); + if (exist != null && !Objects.equals(exist.getId(), excludeId)) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.CITY_COMPONENT_TYPE_NAME_EXISTS); + } + } +} diff --git a/urbanops-module-garden/src/main/resources/templates/一物一码属性表导入模版.xlsx b/urbanops-module-garden/src/main/resources/templates/一物一码属性表导入模版.xlsx new file mode 100644 index 0000000..7ee1afb Binary files /dev/null and b/urbanops-module-garden/src/main/resources/templates/一物一码属性表导入模版.xlsx differ diff --git a/urbanops-server/src/main/resources/application-prod.yaml b/urbanops-server/src/main/resources/application-prod.yaml index 4daf0c7..2093ee3 100644 --- a/urbanops-server/src/main/resources/application-prod.yaml +++ b/urbanops-server/src/main/resources/application-prod.yaml @@ -152,17 +152,17 @@ logging: name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 level: # 配置自己写的 MyBatis Mapper 打印日志 - com.zteits.module.bpm.dal.mysql: debug - com.zteits.module.infra.dal.mysql: debug + com.zteits.module.bpm.dal.mysql: INFO + com.zteits.module.infra.dal.mysql: INFO com.zteits.module.infra.dal.mysql.logger.ApiErrorLogMapper: INFO # 配置 ApiErrorLogMapper 的日志级别为 info,避免和 GlobalExceptionHandler 重复打印 com.zteits.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info com.zteits.module.infra.dal.mysql.file.FileConfigMapper: INFO # 配置 FileConfigMapper 的日志级别为 info #com.zteits.module.pay.dal.mysql: debug #com.zteits.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 PayNotifyTaskMapper 的日志级别为 info - com.zteits.module.system.dal.mysql: debug + com.zteits.module.system.dal.mysql: INFO com.zteits.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 配置 SmsChannelMapper 的日志级别为 info - com.zteits.module.tool.dal.mysql: debug - com.zteits.module.workorder.dal.mysql: debug + com.zteits.module.tool.dal.mysql: INFO + com.zteits.module.workorder.dal.mysql: INFO #com.zteits.module.member.dal.mysql: debug #com.zteits.module.trade.dal.mysql: debug #com.zteits.module.promotion.dal.mysql: debug -- libgit2 0.21.4