# Ether 空间节点管理架构设计方案

**版本**: v2.0  
**设计日期**: 2026-02-16  
**设计目标**: 重构空间节点管理，统一空间体系，支持地图服务对接

---

## 一、业务背景与需求分析

### 1.1 物业行业空间管理标准

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                        物业项目空间层级标准模型                                │
└─────────────────────────────────────────────────────────────────────────────┘

项目 (Project)
├── 住宅区域 (Residential Area)
│   ├── 分期 (Phase) ──────────────────── 可选层级，大型项目使用
│   │   ├── 楼栋 (Building)
│   │   │   ├── 单元 (Unit)
│   │   │   │   ├── 楼层 (Floor) ──────── 可选层级
│   │   │   │   │   └── 房间 (Room)
│   │   │   │   └── 房间 (Room)
│   │   │   └── 公共区域 (Public Area)
│   │   └── 地下车库 (Underground Garage)
│   │       └── 车位 (Parking Space)
│   └── 地面停车场 (Surface Parking)
│       └── 车位 (Parking Space)
├── 商业区域 (Commercial Area)
│   ├── 商铺 (Shop)
│   └── 公共区域 (Public Area)
├── 公共设施区域 (Facility Area)
│   ├── 设备房 (Equipment Room)
│   ├── 物业用房 (Property Office)
│   └── 配套设施 (Supporting Facility)
└── 室外区域 (Outdoor Area)
    ├── 道路 (Road)
    ├── 绿化带 (Green Belt)
    └── 景观设施 (Landscape)
```

### 1.2 核心业务需求

| 需求分类 | 具体需求 | 优先级 |
|----------|----------|--------|
| **空间层级管理** | 支持项目→楼栋→单元→房间的层级结构 | P0 |
| **空间类型管理** | 支持楼栋、单元、房间、车位、商铺、公共区域等类型 | P0 |
| **项目统计** | 自动统计楼栋数、户数、车位数等 | P0 |
| **批量导入** | Excel批量导入楼栋、单元、房间数据 | P0 |
| **地图定位** | 支持高德地图标注点位和区域 | P1 |
| **空间编码** | 自动生成空间编码规则 | P1 |
| **业务关联** | 与工单、巡检、收费等业务模块关联 | P1 |
| **可视化展示** | 树形结构展示、地图展示 | P1 |

### 1.3 地图服务需求

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           地图服务对接需求                                    │
└─────────────────────────────────────────────────────────────────────────────┘

1. 点位标注 (Point)
   - 楼栋位置：标注楼栋在地图上的位置
   - 车位位置：标注车位在地图上的位置
   - 设施位置：标注公共设施的位置
   - 巡检点：标注巡检点位

2. 区域绘制 (Polygon)
   - 项目边界：绘制项目的地理边界
   - 区域划分：绘制管理区域边界
   - 车位区域：绘制停车场区域

3. 路径规划 (Polyline)
   - 巡检路线：规划巡检路线
   - 巡逻路线：规划安保巡逻路线

4. 地图交互
   - 点击查询：点击地图元素查看详情
   - 区域筛选：在地图上框选筛选
   - 距离测量：测量两点间距离
```

---

## 二、数据模型设计

### 2.1 统一空间节点模型

**设计原则**：
1. 所有空间实体统一使用 `mdm_space_node` 表
2. 通过 `node_type` 区分不同类型
3. 通过 `node_category` 区分大类（建筑、车位、设施）
4. 支持树形结构和地图数据

```sql
-- ============================================================
-- 空间节点主表 (统一管理所有空间实体)
-- ============================================================
CREATE TABLE mdm_space_node (
    -- 主键
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    
    -- 基础属性
    project_id          UUID NOT NULL REFERENCES mdm_project(id),
    code                VARCHAR(50) NOT NULL,           -- 空间编码
    name                VARCHAR(100) NOT NULL,          -- 空间名称
    full_name           VARCHAR(500),                   -- 全路径名称
    short_name          VARCHAR(50),                    -- 简称
    
    -- 类型分类
    node_category       VARCHAR(20) NOT NULL,           -- 节点大类: BUILDING/PARKING/FACILITY/AREA
    node_type           VARCHAR(30) NOT NULL,           -- 节点类型: BUILDING/UNIT/ROOM/PARKING/SHOP等
    usage_type          VARCHAR(30),                    -- 用途类型: RESIDENTIAL/COMMERCIAL/OFFICE等
    
    -- 树形结构
    parent_id           UUID REFERENCES mdm_space_node(id),
    tree_path           VARCHAR(1000),                  -- 物理路径: id.id.id
    tree_path_name      VARCHAR(1000),                  -- 名称路径: 项目/楼栋/单元/房间
    level               INTEGER DEFAULT 0,              -- 层级深度
    sort_order          INTEGER DEFAULT 0,              -- 排序号
    
    -- 状态管理
    status              VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
    delivery_status     VARCHAR(20),                    -- 交付状态: UNDELIVERED/DELIVERED
    decoration_status   VARCHAR(20),                    -- 装修状态: ROUGH/FINE/UNDONE
    
    -- 面积信息
    building_area       NUMERIC(10,2),                  -- 建筑面积(㎡)
    usable_area         NUMERIC(10,2),                  -- 使用面积(㎡)
    shared_area         NUMERIC(10,2),                  -- 公摊面积(㎡)
    land_area           NUMERIC(10,2),                  -- 占地面积(㎡)
    
    -- 地理信息
    longitude           NUMERIC(10,6),                  -- 经度
    latitude            NUMERIC(10,6),                  -- 纬度
    location            GEOMETRY(Point, 4326),          -- PostGIS点位
    boundary            GEOMETRY(Polygon, 4326),        -- PostGIS区域边界
    altitude            NUMERIC(8,2),                   -- 海拔高度
    floor_number        INTEGER,                        -- 楼层号(正数地上,负数地下)
    
    -- 地址信息
    province            VARCHAR(50),                    -- 省
    city                VARCHAR(50),                    -- 市
    district            VARCHAR(50),                    -- 区
    street              VARCHAR(100),                   -- 街道
    address             VARCHAR(255),                   -- 详细地址
    
    -- 扩展属性(JSON)
    attributes          JSONB,                          -- 类型特定属性
    
    -- 系统字段
    created_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_by          UUID,
    updated_by          UUID,
    is_deleted          BOOLEAN DEFAULT FALSE,
    
    -- 约束
    CONSTRAINT uk_space_node_project_code UNIQUE (project_id, code)
);

-- 索引
CREATE INDEX idx_space_node_project ON mdm_space_node(project_id);
CREATE INDEX idx_space_node_parent ON mdm_space_node(parent_id);
CREATE INDEX idx_space_node_type ON mdm_space_node(node_type);
CREATE INDEX idx_space_node_tree_path ON mdm_space_node(tree_path);
CREATE INDEX idx_space_node_location ON mdm_space_node USING GIST(location);
CREATE INDEX idx_space_node_boundary ON mdm_space_node USING GIST(boundary);
CREATE INDEX idx_space_node_attributes ON mdm_space_node USING GIN(attributes);
```

### 2.2 节点类型与属性定义

```java
/**
 * 空间节点大类
 */
public enum SpaceNodeCategory {
    BUILDING("建筑空间", "楼栋、单元、房间等建筑空间"),
    PARKING("停车空间", "车位、车库等停车空间"),
    FACILITY("设施空间", "设备房、公共设施等"),
    AREA("区域空间", "公共区域、管理区域等");
}

/**
 * 空间节点类型
 */
public enum SpaceNodeType {
    // 建筑空间
    BUILDING("楼栋", SpaceNodeCategory.BUILDING, 1),
    UNIT("单元", SpaceNodeCategory.BUILDING, 2),
    FLOOR("楼层", SpaceNodeCategory.BUILDING, 3),
    ROOM("房间", SpaceNodeCategory.BUILDING, 4),
    SHOP("商铺", SpaceNodeCategory.BUILDING, 2),
    
    // 停车空间
    GARAGE("车库", SpaceNodeCategory.PARKING, 1),
    PARKING_AREA("停车区域", SpaceNodeCategory.PARKING, 2),
    PARKING_SPACE("车位", SpaceNodeCategory.PARKING, 3),
    
    // 设施空间
    EQUIPMENT_ROOM("设备房", SpaceNodeCategory.FACILITY, 1),
    PROPERTY_OFFICE("物业用房", SpaceNodeCategory.FACILITY, 1),
    SECURITY_ROOM("门岗", SpaceNodeCategory.FACILITY, 1),
    
    // 区域空间
    PUBLIC_AREA("公共区域", SpaceNodeCategory.AREA, 1),
    GREEN_AREA("绿化区域", SpaceNodeCategory.AREA, 1),
    ROAD("道路", SpaceNodeCategory.AREA, 1);
}
```

### 2.3 类型特定属性 (JSONB)

```json
// 楼栋属性
{
  "buildingType": "RESIDENTIAL",        // 楼栋类型: RESIDENTIAL/COMMERCIAL/MIXED
  "structureType": "FRAME",             // 结构类型: FRAME/BRICK/STEEL
  "totalFloors": 18,                    // 总层数
  "undergroundFloors": 1,               // 地下层数
  "totalUnits": 4,                      // 单元数
  "totalRooms": 144,                    // 房间数
  "elevatorCount": 2,                   // 电梯数
  "completionDate": "2020-06-30",       // 竣工日期
  "developer": "XX房地产开发公司"         // 开发商
}

// 单元属性
{
  "unitType": "STANDARD",               // 单元类型
  "elevatorCount": 1,                   // 电梯数
  "stairType": "DOUBLE_RUN",            // 楼梯类型
  "roomsPerFloor": 2                    // 每层户数
}

// 房间属性
{
  "roomType": "APARTMENT",              // 房间类型: APARTMENT/VILLA/SHOP/OFFICE
  "layoutType": "3T2",                  // 户型: 3室2厅2卫
  "roomCount": 3,                       // 卧室数
  "livingRoomCount": 2,                 // 客厅数
  "bathroomCount": 2,                   // 卫生间数
  "kitchenCount": 1,                    // 厨房数
  "balconyCount": 1,                    // 阳台数
  "orientation": "SOUTH",               // 朝向
  "propertyCertificateNo": "沪房地徐字(2020)第0001号"  // 房产证号
}

// 车位属性
{
  "parkingType": "UNDERGROUND",         // 车位类型: UNDERGROUND/SURFACE/MECHANICAL
  "parkingCategory": "STANDARD",        // 车位类别: STANDARD/LARGE/DISABLED
  "vehicleType": "CAR",                 // 车辆类型: CAR/SUV/VAN
  "hasChargingPile": false,             // 是否有充电桩
  "zoneCode": "A",                      // 区域编码
  "rowNumber": 1,                       // 排号
  "columnNumber": 5                     // 列号
}

// 商铺属性
{
  "shopType": "RETAIL",                 // 商铺类型: RETAIL/CATERING/SERVICE
  "frontage": 8.5,                      // 门面宽度(米)
  "depth": 12.0,                        // 进深(米)
  "ceilingHeight": 4.5,                 // 层高(米)
  "hasMezzanine": false,                // 是否有夹层
  "businessLicense": "XXX"              // 营业执照
}
```

### 2.4 项目统计视图

```sql
-- 项目统计视图（实时计算）
CREATE OR REPLACE VIEW v_project_statistics AS
SELECT 
    p.id AS project_id,
    p.code AS project_code,
    p.name AS project_name,
    
    -- 建筑统计
    COUNT(DISTINCT CASE WHEN sn.node_type = 'BUILDING' THEN sn.id END) AS total_buildings,
    COUNT(DISTINCT CASE WHEN sn.node_type = 'UNIT' THEN sn.id END) AS total_units,
    COUNT(DISTINCT CASE WHEN sn.node_type = 'ROOM' THEN sn.id END) AS total_rooms,
    
    -- 车位统计
    COUNT(DISTINCT CASE WHEN sn.node_type = 'PARKING_SPACE' THEN sn.id END) AS total_parking,
    COUNT(DISTINCT CASE WHEN sn.node_type = 'PARKING_SPACE' AND ps.status = 'AVAILABLE' THEN sn.id END) AS available_parking,
    
    -- 面积统计
    SUM(CASE WHEN sn.node_type = 'ROOM' THEN sn.building_area ELSE 0 END) AS total_building_area,
    SUM(CASE WHEN sn.node_type = 'ROOM' THEN sn.usable_area ELSE 0 END) AS total_usable_area,
    
    -- 入住统计
    COUNT(DISTINCT CASE WHEN sn.node_type = 'ROOM' AND sn.status = 'OCCUPIED' THEN sn.id END) AS occupied_rooms,
    COUNT(DISTINCT CASE WHEN sn.node_type = 'ROOM' AND sn.status = 'VACANT' THEN sn.id END) AS vacant_rooms,
    
    p.updated_at
FROM mdm_project p
LEFT JOIN mdm_space_node sn ON sn.project_id = p.id AND sn.is_deleted = FALSE
GROUP BY p.id, p.code, p.name, p.updated_at;
```

---

## 三、API接口设计

### 3.1 RESTful API 规范

```
基础路径: /api/v1/mdm/space-nodes

┌─────────────────────────────────────────────────────────────────────────────┐
│                           空间节点 API 接口                                   │
└─────────────────────────────────────────────────────────────────────────────┘

1. 基础 CRUD
   POST   /api/v1/mdm/space-nodes                    创建空间节点
   PUT    /api/v1/mdm/space-nodes/{id}               更新空间节点
   DELETE /api/v1/mdm/space-nodes/{id}               删除空间节点
   GET    /api/v1/mdm/space-nodes/{id}               查询空间节点详情

2. 树形结构
   GET    /api/v1/mdm/space-nodes/tree               获取完整树形结构
   GET    /api/v1/mdm/space-nodes/roots              获取根节点列表
   GET    /api/v1/mdm/space-nodes/{id}/children      获取子节点列表
   GET    /api/v1/mdm/space-nodes/{id}/ancestors     获取祖先节点链
   GET    /api/v1/mdm/space-nodes/{id}/descendants   获取所有子孙节点
   PUT    /api/v1/mdm/space-nodes/{id}/move          移动节点到新父节点

3. 类型查询
   GET    /api/v1/mdm/space-nodes/buildings          获取楼栋列表
   GET    /api/v1/mdm/space-nodes/rooms              获取房间列表
   GET    /api/v1/mdm/space-nodes/parking-spaces     获取车位列表
   GET    /api/v1/mdm/space-nodes/shops              获取商铺列表

4. 批量操作
   POST   /api/v1/mdm/space-nodes/batch              批量创建
   PUT    /api/v1/mdm/space-nodes/batch              批量更新
   DELETE /api/v1/mdm/space-nodes/batch              批量删除
   POST   /api/v1/mdm/space-nodes/import             Excel导入
   GET    /api/v1/mdm/space-nodes/export/template    下载导入模板
   GET    /api/v1/mdm/space-nodes/export             导出数据

5. 地图相关
   GET    /api/v1/mdm/space-nodes/map/markers        获取地图标注点
   GET    /api/v1/mdm/space-nodes/map/boundaries     获取区域边界
   PUT    /api/v1/mdm/space-nodes/{id}/location      更新位置信息
   PUT    /api/v1/mdm/space-nodes/{id}/boundary      更新区域边界

6. 统计分析
   GET    /api/v1/mdm/space-nodes/statistics         空间统计数据
   GET    /api/v1/mdm/space-nodes/statistics/by-type 按类型统计
   GET    /api/v1/mdm/space-nodes/statistics/by-status 按状态统计
```

### 3.2 请求/响应示例

**创建楼栋**:
```json
// POST /api/v1/mdm/space-nodes
{
  "projectId": "uuid",
  "code": "B001",
  "name": "1号楼",
  "nodeCategory": "BUILDING",
  "nodeType": "BUILDING",
  "parentId": null,
  "buildingArea": 12000.00,
  "longitude": 121.473701,
  "latitude": 31.230416,
  "attributes": {
    "buildingType": "RESIDENTIAL",
    "totalFloors": 18,
    "undergroundFloors": 1,
    "totalUnits": 4,
    "elevatorCount": 2
  }
}
```

**创建单元**:
```json
{
  "projectId": "uuid",
  "code": "B001-U1",
  "name": "1单元",
  "nodeCategory": "BUILDING",
  "nodeType": "UNIT",
  "parentId": "building-uuid",
  "attributes": {
    "unitType": "STANDARD",
    "elevatorCount": 1,
    "roomsPerFloor": 2
  }
}
```

**批量创建房间**:
```json
// POST /api/v1/mdm/space-nodes/batch
{
  "parentId": "unit-uuid",
  "nodeType": "ROOM",
  "startFloor": 1,
  "endFloor": 18,
  "roomsPerFloor": 2,
  "roomPrefix": "B001-1-",
  "roomTemplate": {
    "nodeCategory": "BUILDING",
    "buildingArea": 89.5,
    "usableArea": 72.3,
    "attributes": {
      "roomType": "APARTMENT",
      "layoutType": "3T2",
      "roomCount": 3,
      "livingRoomCount": 2,
      "bathroomCount": 2
    }
  }
}
```

---

## 四、前端界面设计

### 4.1 页面结构

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           空间节点管理页面                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 工具栏: [新增楼栋] [批量导入] [导出] [切换视图] [地图模式]               │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ ┌───────────────────────┬─────────────────────────────────────────────────┐ │
│ │                       │                                                 │ │
│ │   树形导航 (左侧)      │              内容区域 (右侧)                    │ │
│ │                       │                                                 │ │
│ │   📁 测试小区一期      │   ┌─────────────────────────────────────────┐   │ │
│ │   ├── 🏢 1号楼        │   │  楼栋详情: 1号楼                         │   │ │
│ │   │   ├── 🚪 1单元    │   │  ─────────────────────────────────────── │   │ │
│ │   │   │   ├── 🏠 101  │   │  编码: B001                              │   │ │
│ │   │   │   ├── 🏠 102  │   │  楼层: 18层 (地下1层)                    │   │ │
│ │   │   │   └── ...     │   │  单元: 4个                               │   │ │
│ │   │   ├── 🚪 2单元    │   │  户数: 144户                             │   │ │
│ │   │   └── ...         │   │  电梯: 2部                               │   │ │
│ │   ├── 🏢 2号楼        │   │                                           │   │ │
│ │   ├── 🅿️ 地下车库     │   │  [编辑] [添加单元] [批量添加房间] [删除] │   │ │
│ │   │   ├── 🅿️ A区     │   └─────────────────────────────────────────┘   │ │
│ │   │   └── 🅿️ B区     │                                                 │ │
│ │   └── 🏪 商业街        │   ┌─────────────────────────────────────────┐   │ │
│ │       ├── 🏪 S001     │   │  子节点列表                              │   │ │
│ │       └── 🏪 S002     │   │  ─────────────────────────────────────── │   │ │
│ │                       │   │  [表格: 单元列表/房间列表]                │   │ │
│ │                       │   └─────────────────────────────────────────┘   │ │
│ └───────────────────────┴─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```

### 4.2 地图模式

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           地图模式                                           │
├─────────────────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 工具栏: [绘制项目边界] [标注楼栋] [标注车位] [标注设施] [保存]          │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │                                                                         │ │
│ │                    ┌─────┐                                              │ │
│ │                    │ 1#  │                                              │ │
│ │                    └─────┘         ┌─────┐                              │ │
│ │                                    │ 2#  │                              │ │
│ │    ┌─────┐                        └─────┘                              │ │
│ │    │ 3#  │                                                              │ │
│ │    └─────┘              ┌──────────────────┐                           │ │
│ │                         │   地下车库入口    │                           │ │
│ │    ┌─────┐              └──────────────────┘                           │ │
│ │    │ 4#  │                                                              │ │
│ │    └─────┘                                                              │ │
│ │                                                                         │ │
│ │    ═════════════════════════════════════════════════════════════════   │ │
│ │                         小区主干道                                       │ │
│ │    ═════════════════════════════════════════════════════════════════   │ │
│ │                                                                         │ │
│ │              🌳🌳🌳              🌳🌳🌳                                  │ │
│ │              绿化带              绿化带                                  │ │
│ │                                                                         │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 图层控制: [☑ 楼栋] [☑ 车位] [☑ 设施] [☑ 区域边界] [☐ 巡检路线]        │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```

### 4.3 批量导入模板

**楼栋导入模板**:
| 楼栋编码* | 楼栋名称* | 总层数 | 地下层数 | 单元数 | 建筑面积 | 经度 | 纬度 |
|-----------|-----------|--------|----------|--------|----------|------|------|
| B001 | 1号楼 | 18 | 1 | 4 | 12000 | 121.473701 | 31.230416 |
| B002 | 2号楼 | 18 | 1 | 4 | 12000 | 121.473801 | 31.230516 |

**房间导入模板**:
| 楼栋编码* | 单元编码 | 楼层* | 房间编码* | 房间名称* | 建筑面积 | 使用面积 | 户型 | 房间数 | 客厅数 | 卫生间数 |
|-----------|----------|-------|-----------|-----------|----------|----------|------|--------|--------|----------|
| B001 | U1 | 1 | B001-1-101 | 101室 | 89.5 | 72.3 | 3T2 | 3 | 2 | 2 |
| B001 | U1 | 1 | B001-1-102 | 102室 | 89.5 | 72.3 | 3T2 | 3 | 2 | 2 |

---

## 五、地图服务对接方案

### 5.1 高德地图集成架构

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                        地图服务集成架构                                      │
└─────────────────────────────────────────────────────────────────────────────┘

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│   前端应用        │────▶│   高德地图 JS API │────▶│   高德地图服务    │
│   (Vue3)         │     │   (AMap SDK)     │     │   (云端)         │
└──────────────────┘     └──────────────────┘     └──────────────────┘
         │                        │
         │                        │
         ▼                        ▼
┌──────────────────┐     ┌──────────────────┐
│   后端服务        │     │   地图数据存储    │
│   (Spring Boot)  │     │   (PostGIS)      │
└──────────────────┘     └──────────────────┘
         │                        │
         │                        │
         ▼                        ▼
┌──────────────────────────────────────────────────────────────────────────┐
│                          数据同步流程                                      │
│                                                                          │
│  1. 前端使用高德地图SDK进行标注/绘制                                       │
│  2. 获取标注点经纬度或区域坐标数组                                         │
│  3. 提交到后端API保存                                                      │
│  4. 后端存储到PostGIS字段(location/boundary)                              │
│  5. 支持空间查询(范围内搜索、距离计算等)                                    │
└──────────────────────────────────────────────────────────────────────────┘
```

### 5.2 地图服务接口设计

```java
/**
 * 地图服务接口
 */
public interface MapService {
    
    /**
     * 地理编码：地址转坐标
     */
    GeoLocation geocode(String address);
    
    /**
     * 逆地理编码：坐标转地址
     */
    String reverseGeocode(BigDecimal longitude, BigDecimal latitude);
    
    /**
     * 距离计算
     */
    BigDecimal calculateDistance(BigDecimal lng1, BigDecimal lat1, 
                                  BigDecimal lng2, BigDecimal lat2);
    
    /**
     * 范围查询：查找指定范围内的空间节点
     */
    List<SpaceNode> findWithinRadius(BigDecimal longitude, BigDecimal latitude, 
                                      double radiusMeters);
    
    /**
     * 多边形查询：查找多边形区域内的空间节点
     */
    List<SpaceNode> findWithinPolygon(List<GeoPoint> polygon);
}

/**
 * 高德地图实现
 */
@Service
public class AmapMapServiceImpl implements MapService {
    
    @Value("${amap.api.key}")
    private String apiKey;
    
    @Value("${amap.api.geocode-url}")
    private String geocodeUrl;
    
    // ... 实现方法
}
```

### 5.3 前端地图组件

```vue
<!-- MapEditor.vue -->
<template>
  <div class="map-editor">
    <!-- 地图容器 -->
    <div ref="mapContainer" class="map-container"></div>
    
    <!-- 工具栏 -->
    <div class="map-toolbar">
      <a-space>
        <a-button @click="setMode('marker')" :type="mode === 'marker' ? 'primary' : 'default'">
          标注点位
        </a-button>
        <a-button @click="setMode('polygon')" :type="mode === 'polygon' ? 'primary' : 'default'">
          绘制区域
        </a-button>
        <a-button @click="clearSelection">清除</a-button>
        <a-button type="primary" @click="saveLocation">保存</a-button>
      </a-space>
    </div>
  </div>
</template>

<script setup lang="ts">
import AMapLoader from '@amap/amap-jsapi-loader';

const props = defineProps<{
  modelValue?: {
    longitude?: number;
    latitude?: number;
    boundary?: Array<{ longitude: number; latitude: number }>;
  };
}>();

const emit = defineEmits<{
  'update:modelValue': [value: any];
}>();

let map: any = null;
let marker: any = null;
let polygon: any = null;
let AMap: any = null;

onMounted(async () => {
  AMap = await AMapLoader.load({
    key: 'YOUR_AMAP_KEY',
    version: '2.0',
    plugins: ['AMap.Marker', 'AMap.Polygon', 'AMap.Geocoder']
  });
  
  map = new AMap.Map(mapContainer.value, {
    zoom: 15,
    center: [121.473701, 31.230416]
  });
  
  // 初始化已有标注
  if (props.modelValue?.longitude && props.modelValue?.latitude) {
    addMarker(props.modelValue.longitude, props.modelValue.latitude);
  }
});

function addMarker(lng: number, lat: number) {
  if (marker) marker.setMap(null);
  marker = new AMap.Marker({
    position: [lng, lat],
    draggable: true
  });
  marker.setMap(map);
  map.setCenter([lng, lat]);
}

function saveLocation() {
  const result: any = {};
  
  if (marker) {
    const pos = marker.getPosition();
    result.longitude = pos.lng;
    result.latitude = pos.lat;
  }
  
  if (polygon) {
    const path = polygon.getPath();
    result.boundary = path.map((p: any) => ({
      longitude: p.lng,
      latitude: p.lat
    }));
  }
  
  emit('update:modelValue', result);
}
</script>
```

---

## 六、实施计划

### 6.1 阶段划分

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           实施阶段规划                                       │
└─────────────────────────────────────────────────────────────────────────────┘

阶段一：基础重构 (P0, 预计2周)
├── 数据模型重构
│   ├── 扩展 mdm_space_node 表结构
│   ├── 迁移 ParkingSpace 到 SpaceNode
│   └── 创建统计视图
├── API 接口重构
│   ├── 统一字段命名
│   ├── 完善树形操作接口
│   └── 添加批量操作接口
└── 前端页面重构
    ├── 树形组件集成
    ├── 表单字段对齐
    └── 列表页面优化

阶段二：批量导入 (P0, 预计1周)
├── 导入模板设计
├── Excel解析服务
├── 数据校验逻辑
└── 导入结果反馈

阶段三：地图服务 (P1, 预计2周)
├── 高德地图SDK集成
├── 地图编辑组件
├── 位置数据存储
└── 空间查询功能

阶段四：业务关联 (P1, 预计1周)
├── 工单关联空间节点
├── 巡检点关联空间节点
├── 收费项目关联空间节点
└── 能耗计量点关联
```

### 6.2 技术依赖

| 依赖 | 版本 | 用途 |
|------|------|------|
| PostGIS | 3.x | 空间数据存储和查询 |
| 高德地图 JS API | 2.0 | 前端地图展示和编辑 |
| Apache POI | 5.x | Excel导入导出 |
| EasyExcel | 3.x | 大数据量Excel处理 |

---

## 七、风险与对策

| 风险 | 影响 | 对策 |
|------|------|------|
| 数据迁移风险 | 现有数据丢失 | 先备份，编写迁移脚本，测试验证 |
| 性能风险 | 大型项目查询慢 | 使用CTE递归优化，添加缓存 |
| 地图服务费用 | 高德API调用收费 | 控制调用频率，使用本地缓存 |

---

## 八、开发任务清单 (2026-03-23)

### 8.1 后端任务

| 任务 | 状态 | 说明 |
|------|------|------|
| 重构 SpaceNode 实体 | 待开发 | 按设计文档完善字段 |
| 重构 SpaceNodeType 枚举 | 待开发 | 添加 BUILDING/UNIT/ROOM 等 |
| 重构 SpaceNodeService | 待开发 | 树形结构操作 |
| 重构 SpaceNodeRepository | 待开发 | JPA 查询方法 |
| 重构 SpaceNodeController | 待开发 | RESTful API |
| 添加 DTO 类 | 待开发 | 创建/更新/响应 DTO |
| 编写单元测试 | 待开发 | TDD 模式 |

### 8.2 前端任务

| 任务 | 状态 | 说明 |
|------|------|------|
| 创建 space.ts 类型定义 | 待开发 | TypeScript 类型 |
| 创建 space.ts API | 待开发 | API 函数 |
| 创建空间管理页面 | 待开发 | Space.vue |
| 创建空间树形组件 | 待开发 | 左侧树导航 |
| 创建空间表单组件 | 待开发 | 新增/编辑 |
| E2E 测试验证 | 待开发 | Playwright 测试 |

### 8.3 API 接口清单

| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取空间树 | GET | /api/v1/mdm/space-nodes/tree | 项目空间树 |
| 获取根节点 | GET | /api/v1/mdm/space-nodes/roots | 项目下根节点 |
| 获取节点详情 | GET | /api/v1/mdm/space-nodes/{id} | 节点详情 |
| 创建节点 | POST | /api/v1/mdm/space-nodes | 创建空间节点 |
| 更新节点 | PUT | /api/v1/mdm/space-nodes/{id} | 更新节点 |
| 删除节点 | DELETE | /api/v1/mdm/space-nodes/{id} | 删除节点 |
| 获取子节点 | GET | /api/v1/mdm/space-nodes/{id}/children | 子节点列表 |
| 批量创建 | POST | /api/v1/mdm/space-nodes/batch | 批量创建 |
| 批量导入 | POST | /api/v1/mdm/space-nodes/import | Excel导入 |

---

**文档版本**: v2.0
**最后更新**: 2026-03-23
