跳转至

房源详情集成指南

本文档面向接入众趣 zqsdk 的开发者,说明如何在自己的项目中实现「房源详情」功能。房源详情用于展示房源的基本信息、地图位置、小区照片、经纪人信息等。

本项目的【房源详情】模块是按照众趣房产平台展示端的UI展示和交互效果开发的, 您可以根据您的业务自定义开发UI模块和交互逻辑。


一、功能概述

本项目房源详情模块包含以下功能:

功能 说明
顶部标题栏 显示房源名称,点击可展开/收起详情面板
房源信息面板 展示售价、户型、面积等名值对列表(两列网格布局)
地图位置 房源所在位置的百度地图展示
小区照片 小区实勘图展示,点击可打开图片轮播
经纪人信息 底部工具栏展示经纪人头像、姓名、电话

1.1 数据来源

房源详情数据来自众趣开放平台的房源详情接口,数据结构参考:众趣开放平台 - 房源详情对接接口

1.2 效果预览

房源详情展示


二、接口数据结构

2.1 请求参数

interface GetHouseInfoParams {
  model_id: string  // 模型 ID
  house_id: string  // 房源 ID
}

2.2 响应数据结构

interface HouseInfoResponse {
  code: number           // 状态码,1 表示成功
  msg: string            // 响应消息
  detail_config: number  // 详情配置
  house_info: {
    // 基本信息
    title: string                    // 房源标题
    menu_info: {                     // 房源详情列表
      name: string                   // 字段名
      value: string                  // 字段值
      widthStyle: string             // 展示样式:1-3 单行,4-5 多行
    }[]

    // 地图信息
    address_x: string | null         // 经度(百度地图坐标)
    address_y: string | null         // 纬度(百度地图坐标)

    // 小区照片
    images: string[]                 // 实勘图链接地址

    // 经纪人信息
    middleman: string                // 经纪人姓名
    middleman_img: string            // 经纪人头像
    middleman_tel: string            // 经纪人电话

    // 航拍信息
    hangpaiUrl: string               // 航拍 URL
    hangpai_photo: string            // 航拍封面图

    // 分享信息
    jump_url: string                 // 更多房源地址
    share_title: string              // 微信分享标题
    share_desc: string               // 微信分享描述
    share_img: string                // 微信分享头像
    share_link: string               // 微信分享链接
  }
}

三、集成步骤

3.1 配置环境变量

.env 文件中配置:

# 房源详情接口地址
VITE_APP_GET_HOUSE_INFO_API_HOST=https://your-api-host.com

# 百度地图 API 密钥(用于地图展示)
VITE_APP_BAIDU_MAP_AK=your_baidu_map_ak

3.2 实现 API 接口

创建 src/api/getHouseInfo.ts

import axios from 'axios'

const houseInfoApiHost = import.meta.env.VITE_APP_GET_HOUSE_INFO_API_HOST

interface GetHouseInfoParams {
  model_id: string
  house_id: string
}

export const getHouseInfo = async (params: GetHouseInfoParams) => {
  const response = await axios.get(`${houseInfoApiHost}/api/v1/house_info`, {
    headers: { 'Content-Type': 'application/json' },
    params,
  })
  return response.data
}

3.3 创建状态管理

创建 src/stores/house-info.ts

import { ref } from 'vue'
import { defineStore } from 'pinia'
import { getHouseInfo } from '@/api/getHouseInfo'
import { useUrlParams } from '@/stores/url-params'

interface CommonHouseInfoData {
  address_x: string | null
  address_y: string | null
  jump_url: string
  hangpaiUrl: string
  hangpai_photo: string
  menu_info: { widthStyle: string; name: string; value: string }[]
  middleman: string
  middleman_img: string
  middleman_tel: string
  share_desc: string
  share_img: string
  share_link: string
  share_title: string
  title: string
  images: string[]
}

export const useHouseInfoStore = defineStore('houseInfo', () => {
  const houseDetailPanelVisible = ref(false)
  const houseInfo = ref<CommonHouseInfoData | null>(null)
  const houseTopBarVisible = ref(false)

  async function initHouseInfo(): Promise<void> {
    const urlParams = useUrlParams()
    const modelId = urlParams.modelId
    const houseId = urlParams.houseId

    if (!modelId || !houseId) {
      console.warn('参数缺失, 无法获取房源信息')
      return
    }

    try {
      const res = await getHouseInfo({ model_id: modelId, house_id: houseId })
      if (res.code === 1) {
        setHouseInfo(res.house_info)
        showHouseTopBar()
      }
    } catch (error) {
      console.error('初始化房源信息失败', error)
    }
  }

  function setHouseInfo(data: CommonHouseInfoData): void {
    houseInfo.value = data
  }

  function toggleHouseDetailPanelVisible(): void {
    houseDetailPanelVisible.value = !houseDetailPanelVisible.value
  }

  function closeHouseDetailPanel(): void {
    houseDetailPanelVisible.value = false
  }

  function showHouseTopBar(): void {
    houseTopBarVisible.value = true
  }

  return {
    houseDetailPanelVisible,
    houseInfo,
    houseTopBarVisible,
    initHouseInfo,
    setHouseInfo,
    toggleHouseDetailPanelVisible,
    closeHouseDetailPanel,
    showHouseTopBar,
  }
})

3.4 初始化时机

由于房源详情信息与zqsdk的生命周期无关,所以可在任意时刻获取房源详情信息,他不依赖zqsdk的回调消息。本demo项目在vr初始化的时候获取的房源详情信息

src\modules\pc\vr-player\NestVrPlayer.vue 23-29

onMounted(async () => {
  // 初始化url参数,通过urlParam store模块统一管理
  urlParams.initUrlParams()

  await houseInfoStore.initHouseInfo() // 初始化房源信息,获取房源详情
  await vrStore.initSdk() // 初始化 SDK, VR渲染
})

四、UI 组件实现

4.1 组件架构

组件 路径 职责
NestHouseTopBar src/modules/pc/house-info/ 顶部标题栏,点击展开/收起详情
NestHouseDetailPanel src/modules/pc/house-info/ 详情面板容器,组合子组件
NestHouseInfo src/components/common/pc/ 房源信息列表(公共组件)
NestHouseMap src/components/common/pc/ 百度地图(公共组件)
NestCommunityPhotos src/components/common/pc/ 小区照片(公共组件)
NestModalImgSwiper src/components/common/pc/ 图片轮播弹层(公共组件)
NestBottomBar src/modules/pc/toolbar/ 底部工具栏(含经纪人信息)

4.2 顶部标题栏

NestHouseTopBar.vue - 显示房源名称,点击切换详情面板:

<script setup lang="ts">
import { computed, watch } from 'vue'
import { useHouseInfoStore } from '@/stores/house-info'
import { useVrStore } from '@/stores/vr'
import { useIntroduceStore } from '@/stores/introduce'

const houseInfoStore = useHouseInfoStore()
const vrStore = useVrStore()
const introduceStore = useIntroduceStore()

// VR 就绪且非讲房模式且有标题时显示
const visible = computed(() => 
  vrStore.status === 'ready' && 
  !introduceStore.panelVisible && 
  !!houseInfoStore.houseInfo?.title
)

function handleClick(): void {
  houseInfoStore.toggleHouseDetailPanelVisible()
}

// 讲房模式时自动关闭房源详情面板
watch(() => introduceStore.panelVisible, (visible) => {
  if (visible) houseInfoStore.closeHouseDetailPanel()
})
</script>

<template>
  <div v-if="visible" class="house-top-bar" @click="handleClick">
    <div class="house-top-bar__title">
      {{ houseInfoStore.houseInfo?.title }}
    </div>
    <div class="house-top-bar__chevron">▼</div>
  </div>
</template>

4.3 详情面板

NestHouseDetailPanel.vue - 组合房源信息、地图、小区照片:

<script setup lang="ts">
import { ref, computed } from 'vue'
import { useHouseInfoStore } from '@/stores/house-info'
import NestHouseInfo from '@/components/common/pc/NestHouseInfo.vue'
import NestHouseMap from '@/components/common/pc/NestHouseMap.vue'
import NestCommunityPhotos from '@/components/common/pc/NestCommunityPhotos.vue'
import NestModalImgSwiper from '@/components/common/pc/NestModalImgSwiper.vue'

const houseInfoStore = useHouseInfoStore()
const showCommunitySwiper = ref(false)

// 转换房源信息列表
const houseInfoItems = computed(() => {
  return houseInfoStore.houseInfo?.menu_info?.map((item) => ({
    name: item.name,
    value: item.value,
    widthStyle: Number(item.widthStyle) || 1,
  })) ?? []
})

// 地图坐标
const lng = computed(() => Number(houseInfoStore.houseInfo?.address_x) || undefined)
const lat = computed(() => Number(houseInfoStore.houseInfo?.address_y) || undefined)

// 小区照片
const communityImages = computed(() => houseInfoStore.houseInfo?.images ?? [])
const communityCoverUrl = computed(() => communityImages.value[0] ?? '')

// 点击小区照片,展示轮播并折叠详情面板
function handlePhotoClick(): void {
  houseInfoStore.closeHouseDetailPanel()
  showCommunitySwiper.value = true
}
</script>

<template>
  <!-- 房源详情面板 -->
  <Transition name="panel-fade">
    <div v-if="houseInfoStore.houseDetailPanelVisible" class="house-detail-panel">
      <NestHouseInfo v-if="houseInfoItems.length" :items="houseInfoItems" />
      <NestHouseMap v-if="lng && lat" :lng="lng" :lat="lat" :zoom="15" />
      <NestCommunityPhotos 
        v-if="communityImages.length" 
        :cover-url="communityCoverUrl" 
        :count="communityImages.length"
        @photo-click="handlePhotoClick" 
      />
    </div>
  </Transition>

  <!-- 小区照片轮播弹层 -->
  <NestModalImgSwiper
    v-if="showCommunitySwiper && communityImages.length"
    :images="communityImages"
    :show-close="true"
    @close="showCommunitySwiper = false"
  />
</template>

4.4 经纪人信息(底部工具栏)

NestBottomBar.vue 中展示经纪人信息:

<script setup lang="ts">
import { computed } from 'vue'
import { useHouseInfoStore } from '@/stores/house-info'
import defaultHeadIcon from '@/assets/icons/default_head_icon.png'

const houseInfoStore = useHouseInfoStore()

// 是否有经纪人信息
const hasBrokerInfo = computed(() => {
  const info = houseInfoStore.houseInfo
  return !!(info?.middleman || info?.middleman_tel)
})

// 经纪人头像(无则使用默认头像)
const brokerAvatar = computed(() => 
  houseInfoStore.houseInfo?.middleman_img || defaultHeadIcon
)

// 经纪人姓名
const brokerName = computed(() => houseInfoStore.houseInfo?.middleman || '')

// 经纪人电话
const brokerTel = computed(() => houseInfoStore.houseInfo?.middleman_tel || '')
</script>

<template>
  <div class="bottom-bar__broker">
    <img :src="brokerAvatar" class="bottom-bar__avatar" />
    <template v-if="hasBrokerInfo">
      <div class="bottom-bar__broker-info">
        <span class="bottom-bar__broker-name">{{ brokerName }}</span>
        <span class="bottom-bar__broker-label">经纪人</span>
      </div>
      <span v-if="brokerTel" class="bottom-bar__broker-tel">{{ brokerTel }}</span>
    </template>
    <template v-else>
      <span class="bottom-bar__text">经纪人</span>
    </template>
  </div>
</template>

五、公共组件说明

5.1 NestHouseInfo - 房源信息组件

展示名值对列表,采用两列网格布局。

Props:

属性 类型 默认值 说明
title string '房源信息' 区块标题
items HouseInfoItem[] [] 名值对列表
showMore boolean false 是否显示「查看更多」

HouseInfoItem 类型:

interface HouseInfoItem {
  name: string       // 字段名
  value: string      // 字段值
  widthStyle?: number // 展示样式:1-3 单行,4-5 占满整行
}

5.2 NestHouseMap - 百度地图组件

展示房源位置的百度地图。

Props:

属性 类型 默认值 说明
ak string - 百度地图 API 密钥
lng number - 经度
lat number - 纬度
zoom number 15 缩放级别
showMarker boolean true 是否显示标记点

5.3 NestCommunityPhotos - 小区照片组件

展示小区首图和照片数量。

Props:

属性 类型 默认值 说明
coverUrl string '' 首图 URL
count number 0 照片张数
layout 'single' \| 'double' 'single' 布局模式

Events:

事件 说明
photo-click 点击小区图时触发

5.4 NestModalImgSwiper - 图片轮播组件

全屏图片轮播弹层,支持主图与缩略图联动。

Props:

属性 类型 默认值 说明
images string[] - 图片 URL 列表
autoPlay boolean true 是否自动播放
showClose boolean false 是否显示关闭按钮
loop boolean true 是否循环播放

Events:

事件 说明
close 点击关闭按钮时触发

六、与讲房模式的关系

房源详情与讲房模式相互独立,需要处理以下交互:

  1. 讲房时隐藏顶部栏:通过 introduceStore.panelVisible 判断
  2. 讲房时自动关闭详情面板:监听 introduceStore.panelVisible 变化
  3. 讲房房源信息独立:讲房模块有独立的 NestLectureHouseInfo 组件
// 在 NestHouseTopBar 中
watch(() => introduceStore.panelVisible, (visible) => {
  if (visible) houseInfoStore.closeHouseDetailPanel()
})

七、本仓库实现参考

文件 说明
src/api/getHouseInfo.ts 房源详情 API 接口(含 Mock 数据)
src/stores/house-info.ts 房源详情状态管理
src/types/house-detail.ts 房源详情类型定义
src/modules/pc/house-info/NestHouseTopBar.vue 顶部标题栏组件
src/modules/pc/house-info/NestHouseDetailPanel.vue 详情面板容器组件
src/modules/pc/toolbar/NestBottomBar.vue 底部工具栏(含经纪人信息)
src/components/common/pc/NestHouseInfo.vue 房源信息公共组件
src/components/common/pc/NestHouseMap.vue 百度地图公共组件
src/components/common/pc/NestCommunityPhotos.vue 小区照片公共组件
src/components/common/pc/NestModalImgSwiper.vue 图片轮播公共组件

八、常见问题

8.1 房源详情接口返回为空

检查以下配置: - URL 参数是否包含 m(模型 ID)和 house_id(房源 ID) - 环境变量 VITE_APP_GET_HOUSE_INFO_API_HOST 是否正确配置 - 接口响应的 code 是否为 1

8.2 地图不显示

检查以下配置: - 环境变量 VITE_APP_BAIDU_MAP_AK 是否正确配置 - 房源数据中 address_xaddress_y 是否有值 - 百度地图 API 密钥是否有效 - 是否配置了正确的域名白名单

8.3 经纪人信息不显示

检查房源数据中是否包含以下字段: - middleman:经纪人姓名 - middleman_img:经纪人头像 - middleman_tel:经纪人电话

至少需要 middlemanmiddleman_tel 有值才会显示详细信息。


以上完成即可在你自己的项目中实现房源详情功能。