# 房源详情公共组件设计方案

本文档描述「房源详情展示」相关**公共 UI 组件**的职责划分、接口设计与使用方式。仅参考旧项目 `newui-plus-online` 中 `house-info` 相关模块的**展示效果**，逻辑与结构按本仓库规范从零设计；公共层只负责 UI 渲染，业务层负责数据与交互。

---

## 一、设计原则

1. **公共组件不承载业务逻辑**  
   不依赖 store、router、API；仅通过 **props** 接收展示数据，通过 **事件** 或 **slot** 暴露交互，由业务方决定「点哪里、跳哪里、请求什么」。

2. **三大模块拆成三个独立公共组件**  
   房源信息、地图信息、小区照片各自一个组件，业务方可按需引入、任意组合与排布（如 Tab、Swiper、单列等）。

3. **数据与展示解耦**  
   组件只约定「展示所需的最小数据结构」（如列表项 `{ name, value }`），不约定数据来源；业务方从 store/API 组装后传入。

4. **放置位置**  
   三个组件均放在 `src/components/common/` 下（可与现有 NestErrorDisplay、NestLoadingOverlay 等并列），或新建子目录如 `components/common/house-detail/` 便于归类。

---

## 二、旧项目 UI 参考（仅作展示参考）

| 模块       | 旧项目文件 / 表现 |
|------------|-------------------|
| 房源信息   | `house-info.vue`：标题「房源信息」+ 名值对列表（多列/多行样式）+ 底部「查看更多」按钮区域 |
| 地图信息   | `small-baidu-map.vue`：地图区域 + 底部「查看大地图」条，点击由业务跳转 |
| 小区照片   | `house-img-container.vue`：小区图首图 + 张数角标；可选并排「航拍」入口；样式有单块/双块 |

实现时只参考上述**视觉与信息结构**，不沿用旧项目的 store/事件名/组件名。

---

## 三、三个公共组件设计

### 3.1 房源信息展示组件（NestHouseInfo）

**职责**：展示「房源信息」标题 + 一组名值对列表，可选底部操作区（如「查看更多」）。

**Props 建议**：

| 属性       | 类型     | 必填 | 说明 |
|------------|----------|------|------|
| `title`    | `string` | 否   | 区块标题，默认如「房源信息」 |
| `items`    | `Array<{ name: string, value: string, widthStyle?: number }>` | 否   | 名值对列表；widthStyle 用于控制单行/多行等展示样式（可枚举 1–5 或简化） |
| `showMore` | `boolean` | 否  | 是否显示底部「查看更多」区域（仅控制是否留位，实际内容用 slot） |

**Slots**：

- **default**：可不用；列表由 `items` 驱动渲染。
- **extra** 或 **footer**：底部区域（如「查看更多」按钮），由业务方传入链接或按钮，组件只提供容器与样式。

**事件**：

- 可选 `@item-click(index, item)`，便于业务做统计或跳转；若不做可省略。

**说明**：不请求详情页、不解析 URL；「查看更多」的链接或跳转逻辑全部由业务通过 slot 注入。

---

### 3.2 地图信息组件（NestHouseMap）

**职责**：提供「地图」区块的**容器 UI**（标题区 + 内容区 + 底部条），**不内置具体地图实现**（百度/高德/静态图由业务决定）。

**Props 建议**：

| 属性         | 类型     | 必填 | 说明 |
|--------------|----------|------|------|
| `title`      | `string` | 否   | 区块标题，默认如「地图」 |
| `footerText` | `string` | 否   | 底部条文案，如「查看大地图」；若用 slot 则可不传 |
| `contentHeight` | `string` | 否 | 内容区高度，如 `'200px'`、`'40vh'`，保证有可点击/可嵌入区域 |

**Slots**：

- **default**：地图内容区，由业务方放入百度地图组件、静态图、或 iframe 等。
- **footer**：底部条；若不传则使用 `footerText` + 默认样式，点击由业务监听事件处理。

**事件**：

- `@footer-click`：底部条点击，业务方在此做「打开大地图」等逻辑。

**说明**：公共组件不依赖 vue-baidu-map 等具体地图库，避免与业务技术选型强绑定；业务在 layout 或父组件中引入地图并放入 default slot。

---

### 3.3 小区照片组件（NestCommunityPhotos）

**职责**：展示小区照片的**首图/缩略**与数量角标，可选并排的「航拍」入口区块；纯展示 + 点击上报，不负责打开大图或外链。

**Props 建议**：

| 属性        | 类型     | 必填 | 说明 |
|-------------|----------|------|------|
| `coverUrl`  | `string` | 否   | 首图 URL，无则不显示主图块 |
| `count`     | `number` | 否   | 照片张数，用于角标展示，如「5」 |
| `layout`    | `'single' \| 'double'` | 否 | 单块（仅小区图）或双块（小区图 + 航拍区）；默认 `'single'` |
| `aerialLabel` | `string` | 否 | 航拍入口文案，如「航拍」；双块时显示 |

**Slots**：

- **aerial**：当 `layout === 'double'` 时，航拍区块内容可由 slot 完全自定义（图标+文案+样式）；不传则用 `aerialLabel` + 默认样式。

**事件**：

- `@photo-click`：点击小区图区域，参数可选 `(index)` 或 `(e)`，业务方用于打开轮播/大图/统计。
- `@aerial-click`：点击航拍区块，业务方用于跳转外链或打开航拍页。

**说明**：不区分「讲房用图」与「普通用图」；业务方在组装数据时过滤好 `images` 再传入 `coverUrl` 与 `count`。不内置轮播组件，大图/轮播由业务用独立组件或页面实现。

---

## 四、业务层使用方式

业务侧（如 `modules/pc` 或 `modules/mobile` 下的某个「房源详情」业务组件）：

1. **按需引入**：只引用用到的模块，例如只用到「房源信息 + 地图」则只引入 `NestHouseInfo`、`NestHouseMap`。
2. **数据来源**：从 Pinia store 或 API 获取 `houseInfo`、`address`、`communityImages` 等，整理成上述 props 所需结构（如 `items`、`coverUrl`、`count`）。
3. **布局与容器**：由业务决定三个模块的排布方式——例如 Swiper 多页、Tab 切换、单列折叠等；公共组件不包含 Swiper/Tab 等容器逻辑。
4. **交互**：在业务组件内监听 `@footer-click`、`@photo-click`、`@aerial-click`，执行跳转、打开弹窗、打点等。

示例（伪代码）：

```vue
<!-- 业务组件：房源详情面板 -->
<template>
  <div class="business-house-detail">
    <NestHouseInfo
      :title="t('houseInfoTitle')"
      :items="houseInfoItems"
      :show-more="!!detailUrl"
    >
      <template #footer>
        <a v-if="detailUrl" :href="detailUrl" target="_blank">{{ t('houseInfoMore') }}</a>
      </template>
    </NestHouseInfo>

    <NestHouseMap :footer-text="t('lookMapMore')" @footer-click="openBigMap">
      <template #default>
        <BaiduMap v-bind="mapProps" />  <!-- 业务自选地图组件 -->
      </template>
    </NestHouseMap>

    <NestCommunityPhotos
      :cover-url="communityCoverUrl"
      :count="communityImages.length"
      layout="double"
      :aerial-label="t('goAerialUrl')"
      @photo-click="openImageSwiper"
      @aerial-click="goAerial"
    />
  </div>
</template>
```

---

## 五、与旧项目差异小结

| 维度     | 旧项目                     | 本方案（公共组件）                 |
|----------|----------------------------|------------------------------------|
| 数据     | 从 store 直接取 houseInfo  | 仅通过 props 传入，不依赖 store   |
| 地图     | 组件内嵌百度地图           | 仅提供容器 + slot，地图由业务注入 |
| 小区图   | 组件内 filter type、dispatch | 业务过滤后传 coverUrl/count，点击仅 emit |
| 查看更多 | 组件内跳转/公司分支逻辑    | 由 slot 或 footer 事件业务自处理  |
| 容器     | Swiper 在 container 内     | 不包含 Swiper，由业务布局         |

---

## 六、实现顺序建议

1. **NestHouseInfo**：结构简单，先做，便于定稿列表与 footer 的样式规范。  
2. **NestCommunityPhotos**：单块/双块布局与旧项目最接近，可接着做，定稿图片与航拍区样式。  
3. **NestHouseMap**：以「容器 + slot」为主，不依赖地图库，最后做即可。  
4. 在业务模块中做一个**最小可用组合页**（例如只放三个组件 + 简单数据），验证 props/slots/events 是否满足需求，再迭代默认样式与插槽命名。

---

## 七、文档与类型

- 每个公共组件在文件头部用注释说明：职责、props、slots、events；必要时在 `types/` 下增加 `house-detail.ts` 导出 `HouseInfoItem`、`CommunityPhotosProps` 等类型供业务与组件共用。
- 若后续有移动端专用样式，可考虑通过 `layout` 或 class 区分（如 `layout="mobile"`），仍保持单一组件、多端复用。

以上为房源详情三大模块的公共组件设计方案，按此实现可保证「只做 UI、业务自组」的边界清晰，并便于后续扩展（如多语言、主题、无障碍等）。
