Fonrey — 楼盘与区域数据模型(DATA_MODEL_COMPLEX)
所属系统: Fonrey 房产经纪管理系统
版本: v1.0
日期: 2026-04-24
关联模块: apps/complex/ — 楼盘/小区、楼栋、结构(楼层+房号)、区域、学校
一、领域概览(Domain Overview)
核心概念
- Complex(楼盘/小区):房源录入的基础底座。每套房源必须归属于某一楼盘。楼盘数据由运营/数据管理员集中维护,质量直接影响房源录入效率和搜索精度。
- Building(楼栋/单元):楼盘下的物理楼栋,是组织房源位置的第二级。一个楼盘可有多个楼栋(如「1号楼」「2栋2单元」)。
- RoomUnit(房号/结构单元):楼栋内特定楼层的某个房间标识,是房源定位的最细粒度。支持「标准结构」(经运营标准化)和「非标结构」(未归一化)两类。
- District(城区/行政区):行政区划,如静安区、闵行区。
- BusinessArea(商圈/板块):商圈是区域内的细分市场区域,如「南京西路商圈」,一个楼盘可跨多个商圈。
- School(学校):楼盘对口学校,是买家购房决策的核心关注点。一个楼盘可关联多所学校,一所学校可对口多个楼盘。
- MetroLine / MetroStation(地铁线路/站点):楼盘与最近地铁站的距离关系,用于通勤筛选。
关键业务规则
- 楼盘名称不可在编辑页修改:楼盘名称(
name)变更须通过「合并楼盘」或「申请流程」处理,防止经纪人随意改名造成数据混乱。
- 数据锁定机制:楼盘有 4 类锁(楼栋锁/房号锁/信息锁/标准房号锁),锁定后对应数据只有管理员可解锁修改。
- 非标结构处理:未与标准结构关联的房号为「非标」,系统记录非标数量,引导运营逐步消除。
- 搜索依赖全文检索:楼盘名称、别名、地址需维护
search_vector(tsvector)以支持模糊搜索和联想补全。
- 地理坐标优先级:楼盘坐标是区域聚合展示(地图找房)的核心数据,完整度目标 ≥ 90%。
- 学校关联影响房源:从楼盘详情删除对口学校,会级联删除该楼盘下所有房源的对应学区标注。
二、实体关系
三、Schema 定义
3.1 districts — 城区/行政区
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| city |
VARCHAR(50) |
NOT NULL |
所属城市(支持多城市扩展,如「上海」「北京」) |
| name |
VARCHAR(50) |
NOT NULL |
行政区名称,如「静安区」 |
| short_name |
VARCHAR(20) |
|
简称,如「静安」 |
| sort_order |
INTEGER |
NOT NULL DEFAULT 0 |
列表展示排序 |
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
FALSE=已停用(不在筛选项中展示) |
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| updated_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
3.2 business_areas — 商圈/板块
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| district_id |
UUID |
NOT NULL, FK→districts, RESTRICT |
所属城区 |
| name |
VARCHAR(100) |
NOT NULL |
商圈名称 |
| sort_order |
INTEGER |
NOT NULL DEFAULT 0 |
|
| latitude |
NUMERIC(10,7) |
|
商圈中心坐标(纬度) |
| longitude |
NUMERIC(10,7) |
|
商圈中心坐标(经度) |
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
|
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| updated_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
3.3 metro_lines — 地铁线路
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| city |
VARCHAR(50) |
NOT NULL |
所属城市 |
| name |
VARCHAR(50) |
NOT NULL |
线路名,如「1号线」 |
| color |
VARCHAR(7) |
|
线路颜色 HEX(如 #E3002B) |
| sort_order |
INTEGER |
NOT NULL DEFAULT 0 |
|
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
|
3.4 metro_stations — 地铁站点
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| metro_line_id |
UUID |
NOT NULL, FK→metro_lines, CASCADE |
所属线路 |
| name |
VARCHAR(50) |
NOT NULL |
站名 |
| latitude |
NUMERIC(10,7) |
|
站点坐标 |
| longitude |
NUMERIC(10,7) |
|
|
| sort_order |
INTEGER |
NOT NULL DEFAULT 0 |
沿线排序 |
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
|
3.5 schools — 学校
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| district_id |
UUID |
FK→districts, SET NULL |
所属城区 |
| name |
VARCHAR(100) |
NOT NULL |
学校名称 |
| type |
VARCHAR(20) |
|
学校类型:primary=小学 / middle=初中 / high=高中 / k9=九年一贯制 / k12=十二年一贯制 |
| nature |
VARCHAR(20) |
|
学校性质:public=公立 / private=私立 / international=国际学校 |
| level |
VARCHAR(20) |
|
学校等级:normal=普通 / key=重点 / top=名校 |
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
|
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| updated_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
3.6 complexes — 楼盘/小区(核心基础表)
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| name |
VARCHAR(200) |
NOT NULL |
标准楼盘名称,不可在编辑页修改(需走合并/申请流程) |
| district_id |
UUID |
FK→districts, SET NULL |
所属城区 |
| address |
VARCHAR(500) |
|
详细地址(不可在编辑页修改,需走纠错流程) |
| address_summary |
VARCHAR(100) |
|
概要地址(如「海波路1000弄」,可编辑) |
| latitude |
NUMERIC(10,7) |
|
楼盘坐标(纬度),完整度目标 ≥ 90% |
| longitude |
NUMERIC(10,7) |
|
|
| 物业属性 |
|
|
|
| property_usage_types |
VARCHAR(20)[] |
|
物业类型多选:residential/villa/commercial_residential/commercial/office/other |
| building_structure |
VARCHAR(30) |
|
楼栋结构枚举(运营维护):unit_room=单元-房号 / other=其他 |
| building_type |
VARCHAR(20) |
|
建筑类型:slab=板楼 / tower=塔楼 / slab_tower=板塔结合 |
| land_use_years |
VARCHAR(30) |
|
土地使用年限,如「70年」 |
| built_year |
SMALLINT |
|
竣工年份(可多选,存最早竣工年) |
| built_years |
SMALLINT[] |
|
竣工年份多值(楼盘分期竣工) |
| ownership_category |
VARCHAR(30)[] |
|
权属类别多选(运营维护枚举) |
| total_units |
INTEGER |
|
单元总数 |
| total_households |
INTEGER |
|
总户数 |
| 建设信息 |
|
|
|
| total_floor_area |
NUMERIC(12,2) |
|
小区总建筑面积(m²) |
| plot_area |
NUMERIC(12,2) |
|
小区占地面积(m²) |
| plot_ratio |
NUMERIC(5,2) |
|
容积率 |
| green_rate |
NUMERIC(5,2) |
|
绿化率(%) |
| developer |
VARCHAR(200) |
|
开发商 |
| 物业信息 |
|
|
|
| property_company |
VARCHAR(200) |
|
物业公司 |
| property_fee |
NUMERIC(8,2) |
|
物业费(元/m²/月) |
| property_phone |
VARCHAR(30) |
|
物业电话 |
| 停车 |
|
|
|
| parking_total |
INTEGER |
|
车位总数 |
| parking_underground |
INTEGER |
|
地下车位数 |
| parking_ratio |
VARCHAR(20) |
|
停车位配比,如「100:63」 |
| 配套 |
|
|
|
| water_type |
VARCHAR(10) |
|
civil=民水 / commercial=商水 |
| electricity_type |
VARCHAR(10) |
|
civil=民电 / commercial=商电 |
| has_central_heating |
BOOLEAN |
|
是否统一供暖 |
| has_gas |
BOOLEAN |
|
是否有燃气 |
| remarks |
TEXT |
|
备注 |
| 锁定状态 |
|
|
|
| lock_building |
BOOLEAN |
NOT NULL DEFAULT FALSE |
楼栋锁(锁定后不可增删楼栋) |
| lock_room |
BOOLEAN |
NOT NULL DEFAULT FALSE |
房号锁 |
| lock_info |
BOOLEAN |
NOT NULL DEFAULT FALSE |
信息锁(锁定后基本信息只读) |
| lock_standard_room |
BOOLEAN |
NOT NULL DEFAULT FALSE |
标准房号锁 |
| 全文检索 |
|
|
|
| search_vector |
TSVECTOR |
|
由触发器自动维护(name + alias + address) |
| 状态 |
|
|
|
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
FALSE=已停用楼盘 |
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| updated_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| deleted_at |
TIMESTAMPTZ |
|
软删除 |
| created_by |
UUID |
FK→staff, SET NULL |
|
| updated_by |
UUID |
FK→staff, SET NULL |
|
关键索引:
3.7 complex_aliases — 楼盘别名
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| alias |
VARCHAR(200) |
NOT NULL |
别名(最多20字/条,多别名多行存储) |
| is_system |
BOOLEAN |
NOT NULL DEFAULT FALSE |
TRUE=系统/标准别名(只读),FALSE=用户自定义 |
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| created_by |
UUID |
FK→staff, SET NULL |
|
3.8 complex_business_areas — 楼盘与商圈多对多
| 字段 |
类型 |
约束 |
业务说明 |
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| business_area_id |
UUID |
NOT NULL, FK→business_areas, CASCADE |
|
| is_primary |
BOOLEAN |
NOT NULL DEFAULT FALSE |
主商圈(唯一)用于列表显示 |
| PRIMARY KEY |
(complex_id, business_area_id) |
|
|
3.9 complex_schools — 楼盘与学校关联
| 字段 |
类型 |
约束 |
业务说明 |
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| school_id |
UUID |
NOT NULL, FK→schools, CASCADE |
|
| zone_type |
VARCHAR(30) |
|
学区类型:guaranteed=对口 / reference=参考 / lottery=摇号 |
| PRIMARY KEY |
(complex_id, school_id) |
|
|
业务注意:删除此关联记录时,需同步清理对应房源的学区标注(Application 层事务处理)
3.10 complex_metro_stations — 楼盘与地铁站关联
| 字段 |
类型 |
约束 |
业务说明 |
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| station_id |
UUID |
NOT NULL, FK→metro_stations, CASCADE |
|
| distance_meters |
INTEGER |
|
步行距离(米) |
| PRIMARY KEY |
(complex_id, station_id) |
|
|
3.11 buildings — 楼栋/单元
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| name |
VARCHAR(50) |
NOT NULL |
楼栋名,如「1号楼」「A栋2单元」 |
| is_standard |
BOOLEAN |
NOT NULL DEFAULT FALSE |
TRUE=标准结构(经运营核准) |
| property_usage_type |
VARCHAR(20) |
|
物业类型(可与楼盘不同,如商住楼盘内有纯商铺楼栋) |
| built_year |
SMALLINT |
|
竣工年份 |
| total_floors |
SMALLINT |
|
总层数 |
| land_use_years |
VARCHAR(30) |
|
土地使用年限 |
| has_elevator |
BOOLEAN |
|
是否有电梯 |
| school_id |
UUID |
FK→schools, SET NULL |
关联对口学校(楼栋级别的学区差异) |
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
|
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| updated_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| created_by |
UUID |
FK→staff, SET NULL |
|
3.12 room_units — 房号/结构单元(楼层+房间号)
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| building_id |
UUID |
NOT NULL, FK→buildings, CASCADE |
|
| floor |
SMALLINT |
NOT NULL |
楼层(实际层数,地下为负数) |
| floor_name |
VARCHAR(20) |
|
楼层名称展示,如「1层」「B1层」 |
| room_no |
VARCHAR(30) |
NOT NULL |
房号,如「01」「101」 |
| display_no |
VARCHAR(50) |
|
展示用完整房号,如「3-1-101」 |
| is_standard |
BOOLEAN |
NOT NULL DEFAULT FALSE |
TRUE=已归一化为标准结构 |
| is_active |
BOOLEAN |
NOT NULL DEFAULT TRUE |
FALSE=已拆除/不存在 |
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| updated_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
3.13 complex_photos — 楼盘照片
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| category |
VARCHAR(20) |
NOT NULL |
complex=楼盘图 / layout=户型图 / vr=VR全景 / other=其他 |
| file_key |
TEXT |
NOT NULL |
R2/S3 路径 |
| thumbnail_key |
TEXT |
|
缩略图路径 |
| file_name |
VARCHAR(255) |
|
|
| file_size |
INTEGER |
|
bytes |
| width |
INTEGER |
|
|
| height |
INTEGER |
|
|
| is_cover |
BOOLEAN |
NOT NULL DEFAULT FALSE |
楼盘封面图 |
| sort_order |
SMALLINT |
NOT NULL DEFAULT 0 |
|
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| created_by |
UUID |
FK→staff, SET NULL |
|
3.14 complex_attachments — 楼盘附件
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| file_key |
TEXT |
NOT NULL |
|
| file_name |
VARCHAR(255) |
NOT NULL |
|
| file_size |
INTEGER |
|
|
| file_type |
VARCHAR(50) |
|
MIME type |
| sort_order |
SMALLINT |
NOT NULL DEFAULT 0 |
|
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
| created_by |
UUID |
FK→staff, SET NULL |
|
3.15 complex_price_trends — 楼盘价格走势(月度)
| 字段 |
类型 |
约束 |
业务说明 |
| id |
UUID |
PK |
|
| complex_id |
UUID |
NOT NULL, FK→complexes, CASCADE |
|
| record_month |
DATE |
NOT NULL |
月份(统一存为该月1日,如 2026-04-01) |
| avg_sale_price |
NUMERIC(12,2) |
|
月均售价(万元/套) |
| avg_unit_price |
NUMERIC(10,2) |
|
月均单价(元/m²) |
| transaction_count |
INTEGER |
|
成交套数 |
| listing_count |
INTEGER |
|
当月挂牌套数 |
| created_at |
TIMESTAMPTZ |
NOT NULL DEFAULT NOW() |
|
四、枚举常量
complexes.building_type(建筑类型)
complexes.water_type / electricity_type
complex_schools.zone_type(学区类型)
buildings.is_standard / room_units.is_standard
五、查询模式
5.1 楼盘名称联想搜索(录入房源时的自动补全)
5.2 楼盘列表(含房源数量统计)
5.3 查询楼盘下的楼层-房号矩阵(结构管理)
六、触发器
6.1 楼盘全文检索向量(含别名)
七、禁止操作
- ❌ 严禁直接修改 complexes.name:楼盘名称变更必须走「楼盘合并」流程或「管理员申请」,通过 Application 层拦截任何直接 UPDATE
name 字段的操作
- ❌ 严禁硬删除 complexes 记录:有房源关联的楼盘不可删除(
RESTRICT 外键),已有房源的楼盘软删除后房源仍可正常访问
- ❌ 严禁删除 complex_schools 关联而不清理房源学区标注:必须在同一事务中清理对应
property.school_ids 数据
- ❌ 严禁在楼盘坐标为 NULL 时将其用于地图聚合:坐标为空时不参与地图展示,过滤条件:
WHERE latitude IS NOT NULL
- ❌ 严禁在 lock_info=TRUE 时绕过 Application 层直接修改楼盘信息字段:锁定状态必须在服务层检查,不依赖数据库约束
- ❌ 严禁在没有 deleted_at IS NULL 过滤的情况下查询 complexes:楼盘软删除过滤必须存在