ether-docs/02-DESIGN/domains/02-SPACE_NODE_DESIGN.md

35 KiB
Raw Blame History

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. 支持树形结构和地图数据
-- ============================================================
-- 空间节点主表 (统一管理所有空间实体)
-- ============================================================
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 节点类型与属性定义

/**
 * 空间节点大类
 */
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)

// 楼栋属性
{
  "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 项目统计视图

-- 项目统计视图(实时计算)
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 请求/响应示例

创建楼栋:

// 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
  }
}

创建单元:

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

批量创建房间:

// 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 地图服务接口设计

/**
 * 地图服务接口
 */
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 前端地图组件

<!-- 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调用收费 控制调用频率,使用本地缓存

文档版本: v2.0
最后更新: 2026-02-16