Commit d531bc7901a3f60a81e1ccd36ff6cea6ef7332eb

Authored by 王彪总
1 parent eb5be22b

feat(garden): 新增城市部件管理功能并调整生产环境日志级别

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