refactor: 移除未使用的circle-btn组件引用 style: 更新图片资源路径及样式 fix: 修复axios请求配置及类型定义 docs: 添加mock-api.js模拟接口文件
2429 lines
100 KiB
Vue
2429 lines
100 KiB
Vue
<template>
|
||
<page-top-bar></page-top-bar>
|
||
|
||
<div class="content wid1200">
|
||
<div class="header" ref="headerRef">
|
||
<div class="top flexflex">
|
||
<div class="brand-abstract flexflex">
|
||
<div class="flexacenter" style="height: min-content">
|
||
<a class="item" href="/">港校租房</a>
|
||
<img class="arrow" alt="箭头" src="@/assets/img/publicImage/yellow-arrow.svg" />
|
||
<a class="item" href="/apartment">品牌公寓</a>
|
||
<img class="arrow" alt="箭头" src="@/assets/img/publicImage/yellow-arrow.svg" />
|
||
<a class="item" :href="`/apartment?companyid=${company.id}`">{{ company.title }}</a>
|
||
</div>
|
||
</div>
|
||
|
||
<img class="arc-bj" alt="视觉上角的图片" src="@/assets/img/publicImage/angle.png" />
|
||
</div>
|
||
<div class="header-content flexflex">
|
||
<div class="header-left">
|
||
<!-- <image-watch style="z-index: 10000;" arrow="never" :index="imageIndex" :show="imageShow" :close="cloaseImageShow" :list="imageList"></image-watch> -->
|
||
<image-watch arrow="never" :index="imageIndex" v-if="imageShow" :close="cloaseImageShow"
|
||
:list="imageList"></image-watch>
|
||
<div class="slideshow">
|
||
<el-carousel :autoplay="false" arrow="never" indicator-position="none" ref="remarkCaruselUp"
|
||
@change="carouselChange">
|
||
<el-carousel-item class="flexcenter" v-for="(item, index) in allCarouselsData" :key="index">
|
||
<img v-if="index >= carouselIndex - 1 && index <= carouselIndex + 1" class="img"
|
||
:src="item['image'] || item['imageurl']" alt="公寓图片"
|
||
@click="cloaseImageShow(allCarouselsData, carouselIndex, 'carousel')" />
|
||
</el-carousel-item>
|
||
</el-carousel>
|
||
<div class="indicate-type flexacenter" v-if="indicateTypeState()">
|
||
<div class="indicate-item"
|
||
:class="{ pitch: allCarouselsData[carouselIndex]['type'] == 'lives' }"
|
||
v-if="info['lives'] && info['lives'].length != 0" @click="slideshowType('lives')">直播
|
||
</div>
|
||
<div class="indicate-item"
|
||
:class="{ pitch: allCarouselsData[carouselIndex]['type'] == 'videos' }"
|
||
v-if="info['videos'] && info['videos'].length != 0" @click="slideshowType('videos')">视频
|
||
</div>
|
||
<div class="indicate-item"
|
||
:class="{ pitch: allCarouselsData[carouselIndex]['type'] == 'attachment' }"
|
||
v-if="info['attachment'] && info['attachment'].length != 0"
|
||
@click="slideshowType('attachment')">图片</div>
|
||
</div>
|
||
|
||
<div class="indicate" v-if="allCarouselsData.length != 0">{{ carouselIndex -
|
||
carouselsconfig[allCarouselsData[carouselIndex]["type"]]["index"] + 1 }}/{{
|
||
carouselsconfig[allCarouselsData[carouselIndex]["type"]]["amount"] }}</div>
|
||
</div>
|
||
<div class="slideshow-across flexflex">
|
||
<div class="slideshow-btn left flexcenter" @click="handleslideshow('left')">
|
||
<img v-if="carouselIndex == 0" class="arrow" alt="不可点击的左箭头切换"
|
||
src="@/assets/img/publicImage/gray-arrow.svg" />
|
||
<img v-else class="arrow rotate180" alt="可点击的左箭头切换"
|
||
src="@/assets/img/publicImage/black-arrow.svg" />
|
||
</div>
|
||
<div ref="slideshowList" class="slideshow-list box no-scrollbar flex1 flexacenter">
|
||
<!-- <div class="item" :class="({ pitch: index == carouselIndex }, `item${index}`)" v-for="(item, index) in allCarouselsData" @click="slideshowItem(index)" :key="index"> -->
|
||
<div class="item" :class="getClass(index)" v-for="(item, index) in allCarouselsData"
|
||
@click="slideshowItem(index)" :key="index">
|
||
<img class="img" alt="公寓图片缩略图" v-lazy="item['thumbnail'] || item['imageurl']" />
|
||
<img class="video-icon" v-if="item['type'] != 'attachment'"
|
||
src="@/assets/img/publicImage/video-icon.svg" />
|
||
</div>
|
||
</div>
|
||
<div class="slideshow-btn flexcenter" @click="handleslideshow('right')">
|
||
<img v-if="carouselIndex == allCarouselsData.length - 1" class="arrow rotate180"
|
||
alt="不可点击的右箭头切换" src="@/assets/img/publicImage/gray-arrow.svg" />
|
||
<img v-else class="arrow" alt="可点击的右箭头切换" src="@/assets/img/publicImage/black-arrow.svg" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-right flex1">
|
||
<img class="header-bj" alt="头部的地图背景"
|
||
src="@/assets/img/apartmentDetail/apartmentDetail-header-bj.jpg" />
|
||
<!-- <img class="header-shade" src="@/assets/img/apartmentDetail/apartmentDetail-header-shade.svg"> -->
|
||
<!-- <div class="tab-box flexflex" v-if="info['tags'] && info['tags'].length != 0">
|
||
<div class="tab-item wordbreak flexcenter" v-for="(item, index) in info['tags']" :key="index">{{ item }}</div>
|
||
</div> -->
|
||
<div class="apartment-name wordbreak" v-if="info['title']">{{ info["title"] }}</div>
|
||
<div class="label-list flexacenter">
|
||
<div class="label-item flexacenter blue" v-if="info.fieldtrips == 1">
|
||
<img class="safety-icon" src="@/assets/img/publicImage/safety-icon.png" />
|
||
实地考察
|
||
</div>
|
||
<div class="label-item flexacenter violet">0服务费</div>
|
||
<div class="label-item red" v-for="(item, index) in info.hottags" :key="index">{{ item }}</div>
|
||
<div class="label-item" v-for="(item, index) in info.tags" :key="index">{{ item }}</div>
|
||
</div>
|
||
|
||
<div class="introduce">
|
||
<div class="introduce-head flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/yellow-diamond.png" />
|
||
<div class="name">{{ company.title }}</div>
|
||
<div class="full-name flex1">{{ info.propaganda }}</div>
|
||
<div class="more flexacenter" v-if="withsameapartments" @click="handleClickNav('eleseEle')">
|
||
同品牌
|
||
<img class="icon" src="@/assets/img/publicImage/black-arrow.svg" />
|
||
</div>
|
||
</div>
|
||
<div class="synopsis wordbreak">{{ info["introduction"] }}</div>
|
||
</div>
|
||
|
||
<div class="place flexflex" v-if="info['address']">
|
||
<div class="place-head flex1 flexacenter">
|
||
<img class="icon" alt="地图-图标" src="@/assets/img/publicImage/location-icon.png" />
|
||
<div class="text flex1 ellipsis">{{ info["address"] }}</div>
|
||
<div class="more flexacenter" @click="handleClickNav('addressEle')">
|
||
地图
|
||
<img class="icon" alt="地图-箭头" src="@/assets/img/publicImage/black-arrow.svg" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="figure flexacenter" v-if="distancePitch?.alias">
|
||
距离
|
||
<div class="school">{{ distancePitch.alias }}</div>
|
||
<template v-if="distancePitch.distance > 0">{{ distancePitch.distance }}km</template>
|
||
<div class="btn" @click="openSelectSchool">[切换院校]</div>
|
||
</div>
|
||
|
||
<div class="vehicle flexflex" v-if="distancePitch.distanceArr?.length > 0">
|
||
<div class="item flexcenter" v-for="(item, index) in distancePitch.distanceArr"
|
||
:key="index">{{ item.text +
|
||
item.duration }}</div>
|
||
<!-- <div class="item flexcenter" v-if="distancePitch?.walking_duration > 0">
|
||
步行{{ calculateDuration(distancePitch.walking_duration) }}
|
||
</div>
|
||
<div class="item flexcenter" v-if="distancePitch?.driving_duration > 0">
|
||
地铁{{ calculateDuration(distancePitch.driving_duration) }}
|
||
</div>
|
||
<div class="item flexcenter" v-if="distancePitch?.transit_duration > 0">
|
||
巴士{{ calculateDuration(distancePitch.transit_duration) }}
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
<!-- <div class="else flexacenter" v-if="withsameapartments">
|
||
<div class="left flexacenter">
|
||
<img class="icon" alt="同品牌其他公寓-图标" src="@/assets/img/apartmentDetail/yellow-diamond.png" />
|
||
同品牌其他公寓
|
||
</div>
|
||
<div class="right flexacenter" @click="handleClickNav('eleseEle')">
|
||
<div class="quantity flexcenter" :aria-label="withsameapartments + '个同品牌其他公寓'">{{ withsameapartments }}</div>
|
||
<img class="icon" alt="同品牌其他公寓-箭头" src="@/assets/img/publicImage/black-arrow.svg" />
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="operate-box-bj flexcenter" v-if="isOperateShow">
|
||
<div class="operate-box flexacenter" aria-label="详情的导航栏">
|
||
<div class="nav-box flexacenter">
|
||
<div class="nav-item flexcenter" :class="{ pitch: navTab == item.value }"
|
||
:aria-label="`${item['name']}-按钮`" v-for="(item, index) in navList" :key="index"
|
||
@click="handleClickNav(item.value)">{{ item["value"] ==
|
||
"roomEle" ? `${item["name"]} ${roomList.length}` : item["name"] }}</div>
|
||
</div>
|
||
<div class="btn-box flexacenter">
|
||
<div class="btn-item transmit-btn flexcenter" @click="handleCollect">
|
||
<img v-if="info.iscollect == 1" alt="收藏图标" class="transmit-icon"
|
||
src="@/assets/img/detail/collectT.png" />
|
||
<img v-else alt="收藏图标" class="transmit-icon" src="@/assets/img/detail/collect.png" />
|
||
收藏
|
||
</div>
|
||
<!-- <div class="btn-item transmit-btn flexcenter" @click="handleTransmit">
|
||
<img alt="转发图标" class="transmit-icon" src="@/assets/img/publicImage/transmit-icon.png" />
|
||
转发
|
||
<transmit-btn :qrcode="qrcode" :title="info['title']" type="apartment"></transmit-btn>
|
||
</div> -->
|
||
<div class="btn-item consult-btn flexcenter" @click="modificationContact">咨询</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="details-box flexflex" ref="detailsBox">
|
||
<div class="flex1">
|
||
<div class="details-left flex1" :class="{ fixed: isFixed }" :style="{ bottom: FixedBottom + 'px' }"
|
||
ref="detailsLeft">
|
||
<div class="special-offer" v-if="info.promotionalactivities" ref="specialEle">
|
||
<img class="special-bj" src="@/assets/img/publicImage/special-bj.svg" />
|
||
<img class="head" src="@/assets/img/publicImage/special-title.png" />
|
||
<img class="gift" src="@/assets/img/publicImage/special-gift.png" />
|
||
<img class="star1" src="@/assets/img/publicImage/special-star-1.png" />
|
||
<img class="star2" src="@/assets/img/publicImage/special-star-2.png" />
|
||
<img class="star3" src="@/assets/img/publicImage/special-star-3.png" />
|
||
<img class="fireworks" src="@/assets/img/publicImage/special-fireworks.png" />
|
||
<div class="board">
|
||
<div class="gray">
|
||
<p class="text" user-select>{{ info.promotionalactivities }}</p>
|
||
</div>
|
||
</div>
|
||
<img class="bottom-white" src="@/assets/img/publicImage/special-bottom-white.svg" />
|
||
<img class="bottom-orange" src="@/assets/img/publicImage/special-bottom-orange.svg" />
|
||
</div>
|
||
|
||
<div class="remark" ref="inspectEle" v-if="spotSum > 0" @click="openInspectPop">
|
||
<div class="head flexacenter">
|
||
<div class="text">寄托实地考察</div>
|
||
<div class="more flexacenter">
|
||
{{ spotSum }}
|
||
<img class="icon" src="@/assets/img/publicImage/arrow-black-down.svg" />
|
||
</div>
|
||
</div>
|
||
<div class="inspect flexacenter">
|
||
<div class="left flex1">
|
||
<div class="info flexacenter">
|
||
<img class="avatar" :src="spotObj.avatar" />
|
||
<div class="username">{{ spotObj.nickname }}</div>
|
||
<img class="label" :src="spotObj.groupimage" />
|
||
</div>
|
||
<div class="explain two-line-text">{{ spotObj.content }}</div>
|
||
</div>
|
||
<img v-if="spotObj.sources[0]?.thumbnail" class="inspect-img"
|
||
:src="spotObj.sources[0]?.thumbnail" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="remark" ref="followEle" v-if="returnSum > 0" @click="openInspectPop">
|
||
<div class="head flexacenter">
|
||
<div class="text">寄托回访</div>
|
||
<div class="more flexacenter">
|
||
{{ returnSum }}
|
||
<img class="icon" src="@/assets/img/publicImage/arrow-black-down.svg" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="return-visit flexacenter" scroll-x>
|
||
<template v-for="(item, index) in remarkList" :key="index">
|
||
<div class="item flex1" v-if="item.typeid == 2">
|
||
<div class="info flexacenter">
|
||
<img class="avatar" :src="item.avatar" />
|
||
<div class="username">{{ item.nickname }}</div>
|
||
<div class="label flexacenter">已入住</div>
|
||
</div>
|
||
<div class="explain two-line-text">{{ item.content }}</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 房间类型 -->
|
||
<div class="type-box" v-if="roomList.length !== 0" ref="roomEle">
|
||
<div class="item flexacenter" v-for="(item, index) in roomList" :key="index">
|
||
<div class="media" v-if="item.thumbnail"
|
||
@click="cloaseImageShow([...item['videos'], ...item['images']], 0, `media${index}`)">
|
||
<img class="icon" :src="item.thumbnail" />
|
||
<img v-if="item.isVideo" class="play" src="@/assets/img/publicImage/video-icon.svg" />
|
||
</div>
|
||
<div class="info flex1">
|
||
<div class="name">{{ item.name }}</div>
|
||
<div class="tags flexflex" v-if="item.allowance || (item.tags && item.tags.length > 0)">
|
||
<div class="tags-item green" v-if="item.allowance">剩余{{ item.allowance }}间</div>
|
||
<div class="tags-item" v-for="(item, index) in item.tags" key="index">{{ item }}
|
||
</div>
|
||
</div>
|
||
<div class="price flexflex">
|
||
<div class="unit">HK$</div>
|
||
<div class="number">{{ item.discountprice || item.price }}</div>
|
||
<div class="month">/月</div>
|
||
|
||
<div class="original" v-if="item.discountprice">HK$ {{ item.price }}/月</div>
|
||
</div>
|
||
</div>
|
||
<div class="btn flexacenter">
|
||
<div v-if="item.iscollection" class="collect flexcenter red"
|
||
@click="roomCollect(item.id, index)">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/collect-red.svg" />
|
||
已收藏
|
||
</div>
|
||
<div v-else class="collect flexcenter" @click="roomCollect(item.id, index)">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/collect-hollow-black.svg" />
|
||
收藏
|
||
</div>
|
||
<div v-if="item.status == 1" class="consult flexcenter" @click="modificationContact">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/consult-icon.png" />
|
||
咨询
|
||
</div>
|
||
<div v-else class="full-rent flexcenter">已租满</div>
|
||
</div>
|
||
</div>
|
||
<!-- <div class="type-item flexacenter" v-for="(item, index) in roomList" :key="index">
|
||
<div class="type-left flex1">
|
||
<div class="type-name">{{ item["name"] }}</div>
|
||
<div class="type-tags flexacenter" v-if="item.allowance || item.tags.length != 0">
|
||
<div class="tags-item flexcenter first" v-if="item.allowance">仅剩{{ item.allowance }}间</div>
|
||
<template v-if="item.tags.length != 0">
|
||
<div class="tags-item flexcenter" v-for="(it, ii) in item.tags" :key="ii">{{ it }}</div>
|
||
</template>
|
||
</div>
|
||
|
||
<div class="media-box flexflex" v-if="item.videos.length != 0 || item.images.length != 0">
|
||
<div class="media-btn flexcenter" @click="handleMediaBtn('left', index)" v-if="item.videos.length + item.images.length > 5">
|
||
<img v-if="mediaBtnstate[index] && mediaBtnstate[index] != 0" class="rotate180 arrow" src="@/assets/img/publicImage/black-arrow.svg" alt="" />
|
||
<img v-else class="arrow" src="@/assets/img/publicImage/gray-arrow.svg" alt="" />
|
||
</div>
|
||
<div class="media-list flexacenter no-scrollbar" :class="`element${index}`">
|
||
<div class="media-item flexcenter" v-for="(it, i) in item['videos']" :key="i" @click="cloaseImageShow([...item['videos'], ...item['images']], i, `media${index}`)">
|
||
<img class="media-img" :alt="`${item['name']}的视频图`" v-lazy="it['thumbnail']" />
|
||
<img class="media-icon" src="@/assets/img/apartmentDetail/media-icon.svg" />
|
||
</div>
|
||
<div class="media-item flexcenter" v-for="(it, i) in item['images']" :key="i" @click="cloaseImageShow([...item['videos'], ...item['images']], item['videos'].length + i, `media${index}`)">
|
||
<img class="media-img" :alt="`${item['name']}的详情图`" v-lazy="it['thumbnail']" />
|
||
</div>
|
||
</div>
|
||
<div class="media-btn flexcenter" @click="handleMediaBtn('right', index)" v-if="item.videos.length + item.images.length > 5">
|
||
<img v-show="mediaBtnstate[index] != 1" class="arrow" src="@/assets/img/publicImage/black-arrow.svg" alt="" />
|
||
<img v-show="mediaBtnstate[index] == 1" class="rotate180 arrow" src="@/assets/img/publicImage/gray-arrow.svg" alt="" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="type-right flexacenter">
|
||
<div class="price-box flexflex">
|
||
<div class="former" v-if="item['discountprice']">HK$ {{ item["price"] }}/月</div>
|
||
<div class="new flexacenter">
|
||
<div class="unit">HK$</div>
|
||
<div class="cost">{{ item["discountprice"] || item["price"] }}</div>
|
||
/月
|
||
</div>
|
||
</div>
|
||
<div class="consult-btn flexcenter" :aria-label="`${item['name']}-咨询按钮`" v-if="item['status'] == 1" @click="modificationContact">咨询</div>
|
||
<div class="full-occupancy flexcenter" v-else>已租满</div>
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
|
||
<!-- 费用说明 -->
|
||
<div class="details-item cost" v-if="costList.length > 0" ref="costEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/cost-icon.png" />
|
||
费用说明
|
||
</div>
|
||
<div class="cost-box">
|
||
<div class="item" v-for="(item, index) in costList" :key="index">
|
||
<div class="head flexacenter">
|
||
<img class="icon" :src="require('@/assets/img/apartmentDetail/' + item.img)" />
|
||
{{ item.name }}
|
||
</div>
|
||
<div class="explain">{{ item.text }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 优惠活动 -->
|
||
<!-- <div class="details-item special-offer" v-if="info['promotionalactivities']" ref="specialEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/special-offer.svg" />
|
||
优惠活动
|
||
</div>
|
||
<div class="text" v-html="info['promotionalactivities']"></div>
|
||
</div> -->
|
||
|
||
<!-- 地址 -->
|
||
<div class="details-item location" v-if="info.address" ref="addressEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/bus-icon.svg" />
|
||
{{ info.location || "交通" }}
|
||
</div>
|
||
<view-map ref="viewMapRef"
|
||
:latlng="{ latitude: info['coordinate'][0], longitude: info['coordinate'][1] }"
|
||
:name="info['address']"></view-map>
|
||
|
||
<template v-if="false">
|
||
<el-popover :width="814" trigger="click" popper-style="padding: 0" :show-arrow="false"
|
||
v-model:visible="showDistance">
|
||
<template #reference>
|
||
<div class="annex-school-box flexacenter">
|
||
<div class="annex-left flex1 flexacenter">
|
||
<div class="annex-school-item flexflex flex1" @click="selectIndex()"
|
||
v-if="specialSchoolDistance">
|
||
<div class="distance-item-value special flexacenter">
|
||
<div class="mileage">{{ specialSchoolDistance.distanceText }}</div>
|
||
<img v-if="specialSchoolDistance.toolText == '步行'" class="tool-icon"
|
||
src="@/assets/img/detail/walk-icon.png" />
|
||
<img v-else class="tool-icon"
|
||
src="@/assets/img/apartmentDetail/subway-icon.png" />
|
||
<div class="tool-time">{{ specialSchoolDistance?.durationText }}
|
||
</div>
|
||
</div>
|
||
<div class="flexcenter">
|
||
<img src="@/assets/img/detail/markIcon.svg" class="marker-icon"
|
||
alt="" />
|
||
</div>
|
||
<div class="alias-text flexcenter">{{ specialSchoolDistance.alias ||
|
||
"都大" }}</div>
|
||
</div>
|
||
|
||
<div class="annex-school-item flexflex flex1"
|
||
v-for="(item, index) in annexSchoolOmit" :key="index"
|
||
@click="selectIndex(item.id)">
|
||
<div class="distance-item-value flexacenter">
|
||
<div class="mileage">{{ item.distanceText || "2.0km" }}</div>
|
||
<img v-if="!item.list[0].publictransport" class="tool-icon"
|
||
src="@/assets/img/detail/walk-icon.png" />
|
||
<img v-else class="tool-icon"
|
||
src="@/assets/img/apartmentDetail/subway-icon.png" />
|
||
<div class="tool-time">{{
|
||
item.list[0]?.publictransport?.durationText2 ||
|
||
item.list[0]?.durationText2 || "41min" }}</div>
|
||
</div>
|
||
<div class="flexcenter">
|
||
<img src="@/assets/img/detail/markIcon.svg" class="marker-icon"
|
||
alt="" />
|
||
</div>
|
||
<div class="alias-text flexcenter">{{ item.alias || "都大" }}</div>
|
||
</div>
|
||
<div class="line-img"></div>
|
||
</div>
|
||
<div class="annex-btn flexcenter">
|
||
<img class="annex-btn-bj" src="@/assets/img/detail/infoBtnBg.svg" />
|
||
更多
|
||
<img class="annex-btn-icon" src="@/assets/img/detail/arrowIcon.svg" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<div class="distance-info-box pos-r"
|
||
:style="{ height: `${50 * annexSchoolList.length + 70}px` }">
|
||
<div class="title-box dis-f al-item jus-x">
|
||
房源
|
||
<img class="distance-arrow" src="@/assets/img/detail/arrow-circle-blue.svg" />
|
||
院校
|
||
<img src="../assets/img/detail/close.png" class="close-icon"
|
||
@click="showDistance = false" alt="" />
|
||
</div>
|
||
<div class="distance-info-data dis-f">
|
||
<div class="distance-info-left">
|
||
<div class="distance-info-left-item flexcenter"
|
||
:class="{ pitch: index == academyPitchIndex }"
|
||
v-for="(item, index) in annexSchoolList" :key="index"
|
||
@click="selectAcademyIndex(index)">{{ item.alias }}</div>
|
||
</div>
|
||
<el-scrollbar ref="elscrollbarRef"
|
||
:style="{ height: 50 * annexSchoolList.length + 'px' }">
|
||
<div class="distance-info-right flex1">
|
||
<div class="distance-header-box flexacenter">
|
||
<div class="flexacenter">
|
||
<div class="distance-header-icon flexcenter">
|
||
<img src="@/assets/img/detail/home.png" alt=""
|
||
class="distance-header-img" />
|
||
</div>
|
||
{{ targetAcademyPitch.school }}
|
||
</div>
|
||
<div class="distance-header-hint">本数据来自高德地图,仅供参考。</div>
|
||
</div>
|
||
|
||
<div class="academy-school-item"
|
||
v-for="(item, index) in targetAcademyPitch.list" :key="index">
|
||
<div class="academy-school-item-header flexacenter">
|
||
<div class="academy-school-item-left flexacenter">
|
||
<div class="academy-school-item-name">{{ item.title }}</div>
|
||
<div class="academy-school-item-number">{{ item.distanceText
|
||
|| "" }}</div>
|
||
</div>
|
||
<div class="academy-school-item-right flexacenter">
|
||
<img v-if="item.publictransport"
|
||
class="academy-school-item-icon"
|
||
src="@/assets/img/apartmentDetail/subway-icon.png" />
|
||
<img v-else class="academy-school-item-icon"
|
||
src="@/assets/img/detail/walk-icon.png" />
|
||
<div class="academy-school-item-time">{{
|
||
item?.publictransport?.durationText
|
||
|| item.durationText || "" }}</div>
|
||
</div>
|
||
<img class="arrow-green"
|
||
src="@/assets/img/detail/arrow-green.svg" />
|
||
</div>
|
||
<div class="academy-school-item-journey"
|
||
v-if="item.publictransport">
|
||
<div class="journey-item flexacenter"
|
||
v-for="(item, index) in item.publictransport.segments"
|
||
:key="index">
|
||
<div class="circle"></div>
|
||
<!-- 步行 骑行 -->
|
||
<div v-if="item.type == 'walking'"
|
||
class="journey-value flex1">步行{{
|
||
item.distanceText }}</div>
|
||
<!-- 地铁 -->
|
||
<div v-else-if="item.type == 'bus' && item.bustype == '地铁线路'"
|
||
class="journey-value flex1 subway flexacenter">
|
||
<div class="subway-name flexcenter">{{ item.name }}
|
||
</div>
|
||
<div class="flex1" style="white-space: nowrap">{{
|
||
item.via_num }}站·{{
|
||
item.durationText }}</div>
|
||
</div>
|
||
<!-- 公交 -->
|
||
<div v-else-if="item.type == 'bus' && item.bustype == '普通公交线路'"
|
||
class="journey-value flex1 bus flexacenter">
|
||
<div class="bus-name flexcenter">{{ item.name }}</div>
|
||
<div class="flex1" style="white-space: nowrap">{{
|
||
item.via_num }}站·{{
|
||
item.durationText }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-scrollbar>
|
||
</div>
|
||
</div>
|
||
</el-popover>
|
||
</template>
|
||
|
||
<!-- 交通 -->
|
||
<div class="traffic-box" v-if="info['traffic']">
|
||
<!-- <div class="traffic-title item-title flexcenter">交通</div> -->
|
||
<div class="traffic-content" v-html="info['traffic']"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 公寓设施 -->
|
||
<div class="details-item apartment-facilities" :class="{ hide: isHideFacilities }"
|
||
v-if="facilitylist.length > 0" ref="facilitiesEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/apartment-facilities.svg" />
|
||
公寓设施
|
||
</div>
|
||
|
||
<div class="facility-box">
|
||
<div class="item" v-for="(item, index) in facilitylist" :key="index">
|
||
<div class="head">{{ item.name }}({{ item.label.length }})</div>
|
||
<div class="label flexflex">
|
||
<div class="label-item flexacenter" v-for="(item, index) in item.label"
|
||
:key="index">
|
||
<img class="icon"
|
||
src="@/assets/img/apartmentDetail/tick-circle-baby-blue.svg" />
|
||
{{ item }}
|
||
</div>
|
||
</div>
|
||
<div class="img-box flexflex" v-if="item.images.length > 0">
|
||
<div class="img-item" v-for="(item, index) in item.images" :key="index"
|
||
@click="openFacilitiesImg(item.imageurl)">
|
||
<img class="icon" :src="item.thumbnail" />
|
||
<div class="name">{{ item.name }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="bottom-btn flexcenter" v-if="isHideFacilities" @click="openFacilities">
|
||
展开全部
|
||
<img class="icon" src="@/assets/img/publicImage/arrow-black-solid.svg" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 房源详情 -->
|
||
<div class="details-item details-message" :class="{ hide: isHideDetails }" v-if="info['message']"
|
||
ref="messageEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/listing-details.png" />
|
||
房源详情
|
||
</div>
|
||
<div class="text" v-html="info['message']"></div>
|
||
<div class="bottom-btn flexcenter" v-if="isHideDetails" @click="openDetails">
|
||
展开全部
|
||
<img class="icon" src="@/assets/img/publicImage/arrow-black-solid.svg" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 公寓设施 -->
|
||
<!-- <div class="details-item apartment-facilities" v-if="info['facilities']" ref="facilitiesEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/apartment-facilities.svg" />
|
||
公寓设施
|
||
</div>
|
||
<div class="facilities-box">
|
||
<template v-for="(item, key) of facilitiesKeyValue" :key="key">
|
||
<div class="facilities-item flexflex" v-if="info['facilities'][key] && info['facilities'][key].length != 0">
|
||
<div class="facilities-header flexflex">
|
||
<div class="item-title">{{ item }}</div>
|
||
</div>
|
||
<div class="facilities-list flexflex flex1">
|
||
<div class="item flexcenter" v-for="(it, i) in info['facilities'][key]" :key="i">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/tick-green.svg" />
|
||
{{ it }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div> -->
|
||
|
||
<!-- 生活 -->
|
||
<div class="details-item life" v-if="info['life']" ref="lifeEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" src="@/assets/img/apartmentDetail/live.png" />
|
||
生活配套
|
||
</div>
|
||
<div class="text" v-html="info['life']"></div>
|
||
</div>
|
||
|
||
<!-- 品牌介绍 -->
|
||
<div class="details-item company" v-if="company" ref="companyEle">
|
||
<div class="details-header flexacenter">
|
||
<img class="icon" style="width: 20px; height: 20px"
|
||
src="@/assets/img/apartmentDetail/introduce-icon.png" />
|
||
品牌介绍
|
||
</div>
|
||
<img class="company-img flexflex" v-lazy="company['imageurl']" />
|
||
<div class="text" v-html="company['introduction']"></div>
|
||
</div>
|
||
|
||
<div class="details-item hint-box">
|
||
<div class="hint-item">
|
||
温馨提示:房源信息均由公寓方/酒店提供并对其真实性、合法性等负责,平台不负责甄别和审核具体内容真实性和有效性等,请务必仔细核实相关信息,谨防上当受骗。</div>
|
||
<div class="hint-item"></div>
|
||
<div class="hint-item flexacenter">公寓/酒店/中介房源推广合作请联系:<a
|
||
@click="copy('ad@gter.net')">ad@gter.net</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="details-right flexacenter" ref="detailsRigth">
|
||
<phoneqrcode type="apartment" :qrcode="qrcode"></phoneqrcode>
|
||
<groupqrcode type="apartment"></groupqrcode>
|
||
<!-- 同品牌公寓 -->
|
||
<div class="same-brand-title flexcenter" v-if="dualBrandList.length != 0" ref="eleseEle">
|
||
<img class="same-brand-icon" src="@/assets/img/apartmentDetail/same-brand.png" />
|
||
同品牌其他公寓
|
||
</div>
|
||
|
||
<same-brand-item v-for="(item, index) in dualBrandList" :item="item" :key="index"></same-brand-item>
|
||
|
||
<div class="same-brand-title like flexcenter" v-if="likeList.length != 0">
|
||
<img class="same-brand-icon" src="@/assets/img/apartmentDetail/same-brand-recommendation.png" />
|
||
猜你喜欢
|
||
</div>
|
||
|
||
<same-brand-item v-for="(item, index) in likeList" :item="item" :key="index"></same-brand-item>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加客服 - 弹窗 -->
|
||
<div class="add-customer-mask flexcenter" v-if="contactReservationState">
|
||
<div class="add-customer-box flexcenter" :class="{ two: customerservicelist.length != 1 }">
|
||
<img class="close" @click="modificationContact" src="@/assets/img/publicImage/circle-close.png" />
|
||
<img class="add-customer-violet" src="@/assets/img/apartmentDetail/add-customer-violet.svg" />
|
||
<img class="add-customer-violet violet2" src="@/assets/img/apartmentDetail/add-customer-violet2.svg" />
|
||
<div class="add-customer-interior flexflex">
|
||
<img class="add-customer-interior-bj bj2" src="@/assets/img/apartmentDetail/add-customer-map2.png" />
|
||
<img class="add-customer-interior-bj bj2"
|
||
src="@/assets/img/apartmentDetail/add-customer-interior-bj2.svg" />
|
||
<img class="add-customer-interior-bj" src="@/assets/img/apartmentDetail/add-customer-map.svg" />
|
||
<img class="add-customer-interior-bj" src="@/assets/img/apartmentDetail/add-customer-interior-bj.svg" />
|
||
|
||
<img class="title" src="@/assets/img/apartmentDetail/add-customer-title.png" />
|
||
|
||
<div class="QR-code-list flexflex">
|
||
<div class="QR-code-item" v-for="(item, index) in customerservicelist" :key="index">
|
||
<div class="QR-code-box flexcenter">
|
||
<div class="top-right-corner"></div>
|
||
<div class="bottom-left-corner"></div>
|
||
<div class="bottom-right-corner"></div>
|
||
<div class="QR-code-chunk flexcenter">
|
||
<img class="QR-code-img" :src="item['image']" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="name flexcenter">{{ item["title"] }}</div>
|
||
<div class="hint flexcenter">微信扫码添加,备注“寄托”</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<footerpage></footerpage>
|
||
<back-to-top></back-to-top>
|
||
|
||
<!-- 选择院校弹窗 -->
|
||
<el-dialog v-model="isSelectSchool" width="600" class="selectSchoolPop" :show-close="false">
|
||
<div class="title-box dis-f al-item jus-x">
|
||
选择院校
|
||
<img src="@/assets/img/detail/close.png" class="close-icon" @click="isSelectSchool = false" />
|
||
</div>
|
||
|
||
<div class="site flexacenter" bind:tap="to_map">
|
||
<img class="site-img" src="@/assets/img/apartmentDetail/orientation.png" />
|
||
<div class="site-text flex1">{{ info.address }}</div>
|
||
<div class="btn flexacenter" @click="openMap">
|
||
地图
|
||
<img class="btn-img" src="@/assets/img/apartmentDetail/arrow-black.svg" />
|
||
</div>
|
||
</div>
|
||
<div class="select-list" ref="selectSchoolRef">
|
||
<div class="select-item flexflex" :class="['item' + item.sid, { pitch: distancePitch.sid == item.sid }]"
|
||
v-for="(item, index) in distanceList" :key="index" @click.stop="selectSchool(item.sid)">
|
||
<div class="select-icon flexcenter">
|
||
<img class="select-img" src="@/assets/img/apartmentDetail/u1834.png" />
|
||
</div>
|
||
<div class="select-info flex1">
|
||
<div class="select-name" v-if="item.name">{{ item.name }}</div>
|
||
<div class="distance flexacenter">
|
||
距离
|
||
<div class="abbreviation">{{ item.alias }}</div>
|
||
<template v-if="item.distance > 0">{{ item.distance }}km</template>
|
||
</div>
|
||
<div class="vehicle flexflex flex1" v-if="distancePitch.distanceArr?.length > 0">
|
||
<div class="item flexcenter" v-for="(item, index) in item.distanceArr" :key="index">{{
|
||
item.text + item.duration }}</div>
|
||
<!-- <div class="item flexcenter" v-if="item.walking_duration > 0">
|
||
步行{{ calculateDuration(item.walking_duration) }}
|
||
</div>
|
||
<div class="item flexcenter" v-if="item.driving_duration > 0">
|
||
地铁{{ calculateDuration(item.driving_duration) }}
|
||
</div>
|
||
<div class="item flexcenter" v-if="item.transit_duration > 0">
|
||
巴士{{ calculateDuration(item.transit_duration) }}
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
<img class="tick" v-if="distancePitch.sid == item.sid"
|
||
src="@/assets/img/apartmentDetail/tick-circle-red.svg" />
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog v-model="isInspectPop" width="600" class="inspectPop" :show-close="false">
|
||
<div class="type flexacenter">
|
||
<div class="item" :class="{ pitch: remarkTypeid == 0 }" @click="cutRemarkType(0)">全部 {{ spotSum + returnSum
|
||
}}
|
||
</div>
|
||
<div class="item" :class="{ pitch: remarkTypeid == 1 }" @click="cutRemarkType(1)">寄托实地考察 {{ spotSum }}</div>
|
||
<div v-if="returnSum > 0" class="item" :class="{ pitch: remarkTypeid == 2 }" @click="cutRemarkType(2)">寄托回访
|
||
{{
|
||
returnSum }}</div>
|
||
</div>
|
||
|
||
<div class="list">
|
||
<template v-for="(item, index) in remarkList" :key="index">
|
||
<div class="item flexflex"
|
||
v-if="remarkTypeid == 0 || (remarkTypeid == 1 && item.typeid == 1) || (remarkTypeid == 2 && item.typeid == 2)">
|
||
<img class="avatar" :src="item.avatar" />
|
||
<div class="remark-content flexflex flex1">
|
||
<div class="type flexacenter" v-if="item.typeid == 1">
|
||
<img class="image" src="@/assets/img/publicImage/inspect-icon.png" />
|
||
寄托实地考察
|
||
</div>
|
||
<div class="type flexacenter" v-else>
|
||
<img class="image" src="@/assets/img/publicImage/return-visit.png" />
|
||
寄托回访
|
||
</div>
|
||
<div class="username flexacenter">
|
||
{{ item.nickname }}
|
||
<div class="checked-in" v-if="item.typeid == 2">已入住</div>
|
||
<img class="image" v-else-if="item.groupimage" :src="item.groupimage" />
|
||
</div>
|
||
<div class="date">{{ item.date }}</div>
|
||
<div class="text">{{ item.content }}</div>
|
||
<div class="media" scroll-x>
|
||
<div class="media-item" v-for="(item, i) in item.sources" :key="i"
|
||
@click="previewImg(index, i)">
|
||
<img class="media-img" :src="item.thumbnail" />
|
||
<img class="media-icon" v-if="item.type == 'videos'"
|
||
src="@/assets/img/publicImage/video-icon.svg" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, onUnmounted, toRefs, watch, getCurrentInstance, nextTick } from "vue";
|
||
import { ElMessage, ElDialog } from "element-plus";
|
||
import { useStore } from "vuex";
|
||
|
||
import pageTopBar from "../components/pageTopBar/pageTopBar.vue";
|
||
import footerpage from "@/components/footer/footer.vue";
|
||
import viewMap from "@/components/public/viewMap.vue";
|
||
import transmitBtn from "@/components/public/transmitBtn.vue";
|
||
import backToTop from "@/components/public/backToTop.vue";
|
||
import imageWatch from "@/components/detail/imageWatch.vue";
|
||
import phoneqrcode from "@/components/public/phoneQRcode.vue";
|
||
import groupqrcode from "@/components/public/group-QRcode.vue";
|
||
import sameBrandItem from "@/components/apartment/sameBrandItem.vue";
|
||
|
||
import api from "@/utils/api";
|
||
|
||
import { useRouter, useRoute } from "vue-router";
|
||
let router = useRouter();
|
||
|
||
const route = useRoute();
|
||
|
||
watch(route, () => {
|
||
uniqid = router.currentRoute.value.query["uniqid"];
|
||
pitchSchool = router.currentRoute.value.query["school"] || "";
|
||
info.value = {};
|
||
roomList.value = [];
|
||
carouselsconfig.value = { lives: {}, videos: {}, attachment: {} };
|
||
navList.value = [];
|
||
navTab.value = "specialEle";
|
||
dualBrandList.value = [];
|
||
contactReservationState.value = false;
|
||
customerservicelist.value = [];
|
||
mediaBtnstate.value = {};
|
||
|
||
slideshowList.value = null;
|
||
// detailsLeft.value = null;
|
||
token = "";
|
||
|
||
carouselIndex.value = 0;
|
||
allCarouselsData.value = [];
|
||
|
||
isHideFacilities.value = false;
|
||
facilitylist.value = [];
|
||
costList.value = [];
|
||
isHideDetails.value = false;
|
||
|
||
// mediaBtnstate.value = {}
|
||
init();
|
||
distanceSchool();
|
||
});
|
||
|
||
let { uniqid } = router.currentRoute.value.query;
|
||
let pitchSchool = route.query.school || 0;
|
||
|
||
import { copyToClipboard, metersToKilometers, secondsToHoursMinutes, calculateDuration, calculateDistance } from "@/utils/util.js";
|
||
|
||
const { proxy } = getCurrentInstance();
|
||
const store = useStore();
|
||
|
||
let imageShow = ref(false); // 查看大图弹窗的状态
|
||
let imageList = ref([]); // 查看大图弹窗的状态
|
||
let imageIndex = ref(0); // 查看大图弹窗的状态
|
||
let imageType = ""; // 查看大图弹窗的状态
|
||
const cloaseImageShow = (list, index, type) => {
|
||
if (list && imageType != type) {
|
||
imageList.value = list;
|
||
imageIndex.value = index;
|
||
imageType = type;
|
||
}
|
||
console.log(imageList.value);
|
||
|
||
imageShow.value = !imageShow.value;
|
||
};
|
||
|
||
// 房间类型
|
||
let roomList = ref([]);
|
||
let info = ref({});
|
||
|
||
let facilitiesKeyValue = {
|
||
// 设施的键值对
|
||
public: "公共",
|
||
kitchen: "餐厨",
|
||
lavatory: "洗手间",
|
||
};
|
||
|
||
let withsameapartments = ref(0); // 其他公寓数量
|
||
let attachment = ref([]); // 轮播图数据
|
||
|
||
let company = {}; // 品牌数据
|
||
let token = "";
|
||
let qrcode = ref(""); // 小程序详情二维码
|
||
|
||
let allCarouselsData = ref([]);
|
||
|
||
const costArr = [
|
||
{
|
||
tab: "lease",
|
||
name: "租期",
|
||
img: "tenancy-term-icon.png",
|
||
},
|
||
{
|
||
tab: "payment",
|
||
name: "付款方式",
|
||
img: "payment-method-icon.png",
|
||
},
|
||
{
|
||
tab: "water",
|
||
name: "水电煤网",
|
||
img: "water-electricity-icon.png",
|
||
},
|
||
{
|
||
tab: "manage",
|
||
name: "管理费",
|
||
img: "management-cost-icon.png",
|
||
},
|
||
{
|
||
tab: "tax",
|
||
name: "印花税",
|
||
img: "stamp-duty-icon.png",
|
||
},
|
||
{
|
||
tab: "clean",
|
||
name: "房间清洁",
|
||
img: "clean-icon.png",
|
||
},
|
||
{
|
||
tab: "sublet",
|
||
name: "转租",
|
||
img: "sublet-icon.png",
|
||
},
|
||
];
|
||
|
||
// 公寓设施
|
||
const facilityKeyName = {
|
||
public: "公用设施",
|
||
service: "公寓服务",
|
||
sport: "运动&娱乐",
|
||
outdoor: "室外设施",
|
||
security: "安保设施",
|
||
room: "房间设施",
|
||
};
|
||
|
||
const facilityArr = ["room", "public", "service", "sport", "outdoor", "security"]; // 公寓设施 顺序
|
||
let facilitylist = ref([]);
|
||
let costList = ref([]);
|
||
|
||
let pitchScreenSchool = ref(0); // 选择的学校
|
||
|
||
onMounted(() => {
|
||
init();
|
||
distanceSchool();
|
||
|
||
let value = localStorage.getItem("apartmentPitchValue");
|
||
if (value) {
|
||
value = JSON.parse(value);
|
||
pitchScreenSchool = value.school;
|
||
}
|
||
});
|
||
|
||
const init = () => {
|
||
proxy.$get("https://api.gter.net/v1/apartment/details", { uniqid }).then((res) => {
|
||
if (res.code != 200) {
|
||
ElMessage.error(res["message"]);
|
||
return;
|
||
}
|
||
let data = res.data;
|
||
|
||
data["roomList"].forEach((element) => {
|
||
element["images"].forEach((element) => {
|
||
element["type"] = "attachment";
|
||
});
|
||
element["videos"].forEach((element) => {
|
||
element["type"] = "videos";
|
||
});
|
||
});
|
||
|
||
const roomListTarget = data.roomList || [];
|
||
|
||
roomListTarget.forEach((element) => {
|
||
let thumbnail = "";
|
||
let isVideo = false;
|
||
if (element.videos && element.videos.length > 0) {
|
||
thumbnail = element.videos[0].thumbnail;
|
||
isVideo = true;
|
||
} else if (element.images && element.images.length > 0) thumbnail = element.images[0].thumbnail;
|
||
|
||
element["thumbnail"] = thumbnail;
|
||
element["isVideo"] = isVideo;
|
||
});
|
||
|
||
roomList.value = roomListTarget;
|
||
|
||
data["info"]["coordinate"] = data["info"]["coordinate"].split(",").map((item) => {
|
||
return +item;
|
||
});
|
||
|
||
const facility = data.info.facility;
|
||
|
||
if (facility) {
|
||
// facility["public"][0].images = ["https://oss.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-5skdX7qqsgFptxhXa6QWi2uePJ5Bg8WFLPIqoYV7MtZCjvF5wr_-kU8uRQ0NDI5", "https://oss.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-5skfHvqqsgFptxhXa6QWi2uePJ5Bg8WFLPIqoYV7MsIAzvG5Ar_-kU8uRQ0NDI5"];
|
||
// facility["public"][1].images = ["https://oss.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-5skdXfqqsgFptxhXa6QWi2uePJ5Bg8WFLPIqoYV7MtdDG6W5Q7_-kU8uRQ0NDI5", "https://oss.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-5skfXnqqsgFptxhXa6QWi2uePJ5Bg8WFLPIqoYV7MtcA2vF5A7_-kU8uRQ0NDI5"];
|
||
|
||
let list = [];
|
||
facilityArr.forEach((key) => {
|
||
const target = facility[key];
|
||
let label = [];
|
||
let images = [];
|
||
if (Array.isArray(target)) {
|
||
target.forEach((element) => {
|
||
label.push(element.name);
|
||
if (element.images.length > 0) {
|
||
element.images.forEach((e) => {
|
||
images.push({
|
||
name: element.name,
|
||
imageurl: e.imageurl,
|
||
thumbnail: e.thumbnail,
|
||
});
|
||
});
|
||
}
|
||
});
|
||
|
||
// target.forEach((element) => {
|
||
// label.push(element.name);
|
||
// if (element.images.length > 0)
|
||
// images.push({
|
||
// name: element.name,
|
||
// img: element.images,
|
||
// });
|
||
// });
|
||
}
|
||
|
||
if (label.length > 0) {
|
||
list.push({
|
||
key,
|
||
name: facilityKeyName[key],
|
||
label,
|
||
images,
|
||
});
|
||
}
|
||
});
|
||
|
||
facilitylist.value = list;
|
||
}
|
||
|
||
// data.info.feedescription['sublet'] = data.info.feedescription['clean']
|
||
|
||
const feedescription = data.info.feedescription;
|
||
if (feedescription) {
|
||
let list = [];
|
||
costArr.forEach((element) => {
|
||
if (feedescription[element.tab]) {
|
||
list.push({
|
||
text: feedescription[element.tab],
|
||
...element,
|
||
});
|
||
}
|
||
});
|
||
costList.value = list;
|
||
}
|
||
|
||
info.value = data["info"];
|
||
attachment.value = data["info"]["attachment"];
|
||
withsameapartments.value = data["withsameapartments"];
|
||
company = data["company"];
|
||
token = data["token"];
|
||
qrcode.value = data["qrcode"];
|
||
|
||
handleAllCarouselsData();
|
||
|
||
document.title = data?.info?.title || "港校租房-品牌公寓详情";
|
||
|
||
nextTick(() => {
|
||
handleNavData();
|
||
getFacilitiesHeight();
|
||
getDetailsHeight();
|
||
getLikeList();
|
||
getMapDistance();
|
||
// if (info.value.fieldtrips == 1)
|
||
getComment();
|
||
});
|
||
|
||
if (data.withsameapartments > 0) dualBrandData();
|
||
});
|
||
};
|
||
|
||
let isHideDetails = ref(false);
|
||
|
||
// 获取详情的高度
|
||
const getDetailsHeight = () => {
|
||
let target = messageEle.value;
|
||
if (target) {
|
||
let height = target.offsetHeight;
|
||
if (height > 820) isHideDetails.value = true;
|
||
}
|
||
};
|
||
|
||
// 切换 详情 显示
|
||
const openDetails = () => {
|
||
isHideDetails.value = false;
|
||
|
||
let target = messageEle.value;
|
||
let header = target.querySelector(".details-header");
|
||
let box = target.querySelector(".text");
|
||
if (target) target.style.height = header.offsetHeight + box.offsetHeight + "px";
|
||
};
|
||
|
||
let isHideFacilities = ref(false);
|
||
// 获取设施的高度
|
||
const getFacilitiesHeight = () => {
|
||
let target = facilitiesEle.value;
|
||
if (target) {
|
||
let height = target.offsetHeight;
|
||
if (height > 820) isHideFacilities.value = true;
|
||
}
|
||
};
|
||
|
||
// 切换 设施 显示
|
||
const openFacilities = () => {
|
||
isHideFacilities.value = !isHideFacilities.value;
|
||
let target = facilitiesEle.value;
|
||
let header = target.querySelector(".details-header");
|
||
let box = target.querySelector(".facility-box");
|
||
if (target) target.style.height = header.offsetHeight + box.offsetHeight + "px";
|
||
};
|
||
|
||
// 点击打开设施图片预览
|
||
const openFacilitiesImg = (current) => {
|
||
const list = facilitylist.value || [];
|
||
let urls = [];
|
||
list.forEach((element) => {
|
||
element.images.forEach((ele) => {
|
||
urls.push({
|
||
imageurl: ele.imageurl,
|
||
thumbnail: ele.thumbnail,
|
||
type: "attachment",
|
||
});
|
||
});
|
||
});
|
||
|
||
const index = urls.findIndex((item) => item.imageurl == current);
|
||
|
||
cloaseImageShow(urls, index, "facilities");
|
||
};
|
||
|
||
let carouselsconfig = ref({ lives: {}, videos: {}, attachment: {} });
|
||
|
||
// 处理 轮播图大图的索引 tab
|
||
const handleAllCarouselsData = () => {
|
||
let targetInfo = { ...info.value };
|
||
|
||
let accumulativeTotal = 0; // 累计
|
||
for (const key in carouselsconfig.value) {
|
||
carouselsconfig.value[key] = {
|
||
amount: targetInfo[key].length,
|
||
index: accumulativeTotal,
|
||
};
|
||
accumulativeTotal += targetInfo[key].length;
|
||
}
|
||
|
||
targetInfo["lives"].forEach((element) => {
|
||
element["type"] = "lives";
|
||
allCarouselsData.value.push(element);
|
||
});
|
||
|
||
targetInfo["videos"].forEach((element) => {
|
||
element["type"] = "videos";
|
||
allCarouselsData.value.push(element);
|
||
});
|
||
|
||
let thumbnailList = targetInfo["thumbnailList"];
|
||
|
||
targetInfo["attachment"].forEach((element, index) => {
|
||
element = {
|
||
imageurl: element,
|
||
thumbnail: thumbnailList[index],
|
||
};
|
||
element["type"] = "attachment";
|
||
allCarouselsData.value.push(element);
|
||
});
|
||
};
|
||
|
||
const roomEle = ref(null);
|
||
const specialEle = ref(null);
|
||
const addressEle = ref(null);
|
||
const messageEle = ref(null);
|
||
const costEle = ref(null);
|
||
const facilitiesEle = ref(null);
|
||
const lifeEle = ref(null);
|
||
const companyEle = ref(null);
|
||
const eleseEle = ref(null);
|
||
const inspectEle = ref(null); // 实地考察 节点
|
||
const followEle = ref(null); // 寄托回访 节点
|
||
|
||
const viewMapRef = ref(null); // 地图组件
|
||
|
||
let navconfig = [
|
||
{
|
||
name: "优惠活动",
|
||
value: "specialEle",
|
||
},
|
||
{
|
||
name: "实地考察",
|
||
value: "inspectEle",
|
||
},
|
||
{
|
||
name: "寄托回访",
|
||
value: "followEle",
|
||
},
|
||
{
|
||
name: "房间类型",
|
||
value: "roomEle",
|
||
},
|
||
{
|
||
name: "费用说明",
|
||
value: "costEle",
|
||
},
|
||
{
|
||
name: "交通",
|
||
value: "addressEle",
|
||
},
|
||
{
|
||
name: "公寓设施",
|
||
value: "facilitiesEle",
|
||
},
|
||
{
|
||
name: "房源详情",
|
||
value: "messageEle",
|
||
},
|
||
{
|
||
name: "生活配套",
|
||
value: "lifeEle",
|
||
},
|
||
{
|
||
name: "品牌介绍",
|
||
value: "companyEle",
|
||
},
|
||
];
|
||
let navList = ref([]);
|
||
|
||
let navTab = ref("specialEle");
|
||
|
||
// 初始化 判断 navTab 值
|
||
const initNavTab = () => {
|
||
if (info.value.promotionalactivities) navTab.value = "specialEle";
|
||
else if (spotSum.value > 0) navTab.value = "inspectEle";
|
||
else if (returnSum.value > 0) navTab.value = "followEle";
|
||
else navTab.value = "roomEle";
|
||
};
|
||
|
||
// 处理 navList 数据
|
||
const handleNavData = () => {
|
||
navList.value = [];
|
||
navconfig.forEach((element) => {
|
||
if (eval(element["value"]).value) navList.value.push(element);
|
||
});
|
||
};
|
||
|
||
// 处理点击nav 滚动事件
|
||
const handleClickNav = (value) => {
|
||
const headerHeight = headerRef.value.getBoundingClientRect().height + 20 + 260 - 36 - 20;
|
||
|
||
let scrollTop = eval(value).value.offsetTop + headerHeight;
|
||
window.scrollTo({ top: scrollTop, behavior: "smooth" });
|
||
};
|
||
|
||
let dualBrandList = ref([]); // 同品牌数据
|
||
// 同品牌请求数据
|
||
const dualBrandData = () => {
|
||
// proxy.$get("/tenement/pc/api/apartment", { token }).then((res) => {
|
||
proxy.$get("https://api.gter.net/v1/apartment/lists", { token }).then((res) => {
|
||
if (res.code != 200) return;
|
||
let data = res.data;
|
||
dualBrandList.value = data.data;
|
||
});
|
||
};
|
||
|
||
// 点击转发的复制链接按钮
|
||
const copy = (value) =>
|
||
copyToClipboard(value).then(() => {
|
||
ElMessage({
|
||
message: "复制成功",
|
||
center: true,
|
||
offset: 320,
|
||
duration: 1000,
|
||
customClass: "message-info",
|
||
});
|
||
});
|
||
|
||
let contactReservationState = ref(false); // 联系预订客服的弹窗状态
|
||
let customerservicelist = ref([]); // 联系预订客服的弹窗状态
|
||
|
||
// 修改 客服 弹窗状态
|
||
const modificationContact = () => {
|
||
if (customerservicelist.value.length == 0) contactReservationService();
|
||
else contactReservationState.value = !contactReservationState.value;
|
||
};
|
||
|
||
// 联系预订客服 请求数据
|
||
const contactReservationService = () => {
|
||
proxy
|
||
.$get("/tenement/pc/api/apartment/customerservice", {
|
||
customerservice: info.value["customerservice"],
|
||
token,
|
||
})
|
||
.then((res) => {
|
||
if (res.code != 200) return;
|
||
let data = res.data;
|
||
customerservicelist.value = data["customerservicelist"];
|
||
contactReservationState.value = !contactReservationState.value;
|
||
});
|
||
};
|
||
|
||
let mediaBtnstate = ref({}); // 0 左边为不能点击 1 右边不能点击 2 是两个都能点击
|
||
|
||
const handleMediaBtn = (type, index) => {
|
||
const element = document.querySelector(`.element${index}`);
|
||
if (element) {
|
||
let left;
|
||
if (type == "left") left = element.scrollLeft - 86;
|
||
else left = element.scrollLeft + 86;
|
||
const scrollOptions = {
|
||
left,
|
||
behavior: "smooth",
|
||
};
|
||
element.scrollTo(scrollOptions);
|
||
|
||
nextTick(() => {
|
||
setTimeout(() => {
|
||
if (element.scrollLeft == 0) mediaBtnstate.value[index] = 0;
|
||
else if (element.scrollLeft + 460 == element.scrollWidth) mediaBtnstate.value[index] = 1;
|
||
else mediaBtnstate.value[index] = 2;
|
||
}, 150);
|
||
});
|
||
}
|
||
};
|
||
|
||
let slideshowList = ref(null); // 轮播图小图的节点
|
||
|
||
let carouselIndex = ref(0); // 轮播图的索引
|
||
|
||
const remarkCaruselUp = ref(null);
|
||
|
||
const carouselChange = (value) => {
|
||
carouselIndex.value = value;
|
||
const element = slideshowList.value;
|
||
const elementchild = element.querySelector(`.item${value}`);
|
||
|
||
let left = elementchild.offsetLeft - element.offsetLeft;
|
||
const scrollOptions = {
|
||
left,
|
||
behavior: "smooth",
|
||
};
|
||
element.scrollTo(scrollOptions);
|
||
};
|
||
|
||
// 顶部轮播图的左右按钮
|
||
const handleslideshow = (type) => {
|
||
if (type == "left" && carouselIndex.value != 0) remarkCaruselUp.value.prev();
|
||
if (type != "left" && carouselIndex.value != allCarouselsData.value.length - 1) remarkCaruselUp.value.next();
|
||
};
|
||
|
||
// 直接点击轮播图的小图就行切换
|
||
const slideshowItem = (index) => remarkCaruselUp.value.setActiveItem(index);
|
||
// 直接点击大图的 类型
|
||
const slideshowType = (type) => slideshowItem(carouselsconfig.value[type].index);
|
||
|
||
let detailsLeft = ref(null);
|
||
let detailsRigth = ref(null);
|
||
|
||
onMounted(() => {
|
||
window.addEventListener("scroll", handleScroll);
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
window.removeEventListener("scroll", handleScroll);
|
||
});
|
||
|
||
let isFixed = ref(false); // 详情左侧是否固定
|
||
let FixedBottom = ref(0); // 详情左侧固定的距离
|
||
|
||
let detailsBox = ref(null); // 详情的节点
|
||
let headerRef = ref(null); // 头部节点
|
||
|
||
let isOperateShow = ref(true); // 底部操作栏是否显示
|
||
|
||
const handleScroll = () => {
|
||
if (Math.random() > 0.3) return;
|
||
let body = document.documentElement ? document.documentElement : document.body ? document.body : document.querySelector(".element");
|
||
let offsetHeight = body.offsetHeight;
|
||
const clientHeight = document.documentElement.clientHeight;
|
||
const scrollTop = document.documentElement.scrollTop;
|
||
const top = scrollTop + clientHeight;
|
||
|
||
const headerHeight = headerRef.value.getBoundingClientRect().height + 20;
|
||
|
||
const left = detailsLeft.value.getBoundingClientRect();
|
||
const rigth = detailsRigth.value.getBoundingClientRect();
|
||
const leftHeight = left.height;
|
||
const rigthHeight = rigth.height;
|
||
|
||
if (leftHeight < rigthHeight) {
|
||
// 整个左边高度到顶部的距离
|
||
const topDistance = 260 - 36 + headerHeight + leftHeight + 223;
|
||
if (top > topDistance && isFixed.value == false) {
|
||
isFixed.value = true;
|
||
FixedBottom.value = document.querySelector(".index-footer").getBoundingClientRect().height + 20;
|
||
}
|
||
|
||
if (top < topDistance && isFixed.value == true) isFixed.value = false;
|
||
}
|
||
|
||
if (scrollTop + clientHeight >= offsetHeight - 200) isOperateShow.value = false;
|
||
else isOperateShow.value = true;
|
||
|
||
for (let i = 0; i < navList.value.length; i++) {
|
||
let element = navList.value[i];
|
||
|
||
const rect = eval(element.value).value.getBoundingClientRect();
|
||
const distanceToTop = rect.top;
|
||
if (distanceToTop >= 0) {
|
||
navTab.value = element.value;
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
const indicateTypeState = () => {
|
||
let total = 0; // 累计
|
||
for (const key in carouselsconfig.value) {
|
||
if (carouselsconfig.value[key]["amount"] > 0) total++;
|
||
}
|
||
|
||
return total > 1 ? true : false;
|
||
};
|
||
|
||
// 公共跳转
|
||
const publicJump = (path) => router.push(path);
|
||
|
||
// 获取 距离学校距离
|
||
const distanceSchool = () => {
|
||
api.detailsDistance({
|
||
uniqid,
|
||
istype: 2,
|
||
}).then((res) => {
|
||
const data = res.data;
|
||
if (res.code != 200) return;
|
||
|
||
let specialSchoolDistanceTarget = null;
|
||
let academyPitchIndexTarget = 0;
|
||
const school = pitchSchool || "";
|
||
let annexSchoolOmitTarget = [];
|
||
data.forEach((element, index) => {
|
||
element["distanceText"] = metersToKilometers(element.distance);
|
||
element.list.forEach((ele) => {
|
||
ele["durationText"] = secondsToHoursMinutes(ele.duration, "chinese");
|
||
ele["durationText2"] = secondsToHoursMinutes(ele.duration);
|
||
ele["distanceText"] = metersToKilometers(ele.distance);
|
||
if (Object.prototype.toString.call(ele.publictransport) === "[object Object]") {
|
||
ele.publictransport["durationText"] = secondsToHoursMinutes(ele?.publictransport?.duration || 0, "chinese");
|
||
ele.publictransport["durationText2"] = secondsToHoursMinutes(ele?.publictransport?.duration || 0);
|
||
const segments = ele.publictransport["segments"];
|
||
if (Array.isArray(segments)) {
|
||
segments.forEach((e) => {
|
||
e["via_num"] = 1 + Math.floor(e.via_num);
|
||
e["durationText"] = secondsToHoursMinutes(e.duration);
|
||
e["distanceText"] = metersToKilometers(e.distance, "chinese");
|
||
});
|
||
}
|
||
} else ele.publictransport = null;
|
||
});
|
||
|
||
if (school == element.id) {
|
||
academyPitchIndexTarget = index;
|
||
const obj = element.list[0] || {};
|
||
let toolText = "步行";
|
||
if (Object.prototype.toString.call(obj.publictransport) === "[object Object]") toolText = "公交地铁";
|
||
specialSchoolDistanceTarget = {
|
||
alias: element.alias,
|
||
distanceText: obj["distanceText"],
|
||
durationText: obj.publictransport?.durationText2 || obj["durationText2"],
|
||
toolText,
|
||
};
|
||
} else annexSchoolOmitTarget.push(element);
|
||
});
|
||
|
||
if (specialSchoolDistanceTarget) annexSchoolOmitTarget = annexSchoolOmitTarget.slice(0, 4);
|
||
else annexSchoolOmitTarget = annexSchoolOmitTarget.slice(0, 5);
|
||
|
||
annexSchoolOmit.value = annexSchoolOmitTarget;
|
||
annexSchoolList.value = data;
|
||
targetAcademyPitch.value = data[academyPitchIndexTarget];
|
||
specialSchoolDistance.value = specialSchoolDistanceTarget;
|
||
academyPitchIndex.value = academyPitchIndexTarget;
|
||
});
|
||
};
|
||
|
||
let annexSchoolOmit = ref([]); // 附近院校 前面 7个 或者 6个的
|
||
let annexSchoolList = ref([]); // 附近院校数据
|
||
let academyPitchIndex = ref(0); // 附近学校距离选中院校 下标
|
||
let targetAcademyPitch = ref({}); // 附近学校距离选中院校 数据
|
||
let specialSchoolDistance = ref(null); // 特殊的 用户带有school参数 则需要特殊显示 学校距离
|
||
const elscrollbarRef = ref(null); // 滚动条
|
||
|
||
// 选择附近学校距离的学校下标
|
||
const selectAcademyIndex = (index) => {
|
||
academyPitchIndex.value = index || 0;
|
||
targetAcademyPitch.value = annexSchoolList.value[academyPitchIndex.value];
|
||
elscrollbarRef.value.setScrollTop(0);
|
||
};
|
||
|
||
// 选择附近学校距离的学校下标
|
||
const selectIndex = (id) => {
|
||
if (!id) id = pitchSchool;
|
||
const data = annexSchoolOmit.value || [];
|
||
data.forEach((element, index) => {
|
||
if (element.id == id) {
|
||
academyPitchIndex.value = index || 0;
|
||
targetAcademyPitch.value = annexSchoolList.value[academyPitchIndex.value];
|
||
}
|
||
});
|
||
|
||
// showDistance.value = true
|
||
};
|
||
|
||
//显示详情
|
||
let showDistance = ref(false);
|
||
|
||
// 点击收藏
|
||
const handleCollect = () => {
|
||
// api.apartmentCollection({ token }).then((res) => {
|
||
proxy.$post("https://api.gter.net/v1/apartment/collection", { token }).then((res) => {
|
||
if (res.code != 200) return;
|
||
const data = res.data;
|
||
info.value.iscollect = data.status || 0;
|
||
ElMessage.success(res.message);
|
||
});
|
||
};
|
||
|
||
// 设置媒体列表的类名
|
||
const getClass = (index) => {
|
||
return {
|
||
pitch: index === carouselIndex.value,
|
||
[`item${index}`]: true,
|
||
};
|
||
};
|
||
|
||
let likeList = ref([]); // 猜你喜欢 数据
|
||
|
||
// 获取猜你喜欢 数据
|
||
const getLikeList = () => {
|
||
proxy.$get("https://api.gter.net/v1/apartment/lists", { token, guess: 1 }).then((res) => {
|
||
if (res.code != 200) return;
|
||
let data = res.data;
|
||
likeList.value = data.data;
|
||
});
|
||
};
|
||
|
||
let isSelectSchool = ref(false); // 选择学校状态
|
||
|
||
let distancePitch = ref({});
|
||
|
||
let distanceList = ref([]);
|
||
|
||
const getMapDistance = () => {
|
||
proxy.$get("https://api.gter.net/v1/apartment/mapDistance", { token }).then((res) => {
|
||
if (res.code != 200) return;
|
||
const data = res.data || [];
|
||
const sid = pitchScreenSchool;
|
||
const distance = data.distance || [];
|
||
distance.sort((a, b) => a.distance - b.distance);
|
||
let arr = [];
|
||
let pitch = null;
|
||
distance.forEach((element) => {
|
||
// let obj = {};
|
||
// element.distance = calculateDistance(element.distance);
|
||
// if (element.walking && element.walking.duration) obj["walking"] = calculateDuration(element.walking.duration);
|
||
// if (element.transit && element.transit.duration) obj["transit"] = calculateDuration(element.transit.duration);
|
||
// if (element.driving && element.driving.duration) obj["driving"] = calculateDuration(element.driving.duration);
|
||
// const target = {
|
||
// name: element.name,
|
||
// distance: element.distance,
|
||
// alias: element.alias,
|
||
// sid: element.sid,
|
||
// obj,
|
||
// };
|
||
// arr.push(target);
|
||
|
||
const keyobj = {
|
||
metrobus_duration: "地铁巴士",
|
||
walking_duration: "步行",
|
||
driving_duration: "地铁",
|
||
transit_duration: "巴士",
|
||
}
|
||
const arr = ["metrobus_duration", "walking_duration", "transit_duration", "driving_duration"]
|
||
let valueArr = []
|
||
|
||
// element['metrobus_duration'] = 6
|
||
// element['walking_duration'] = 6
|
||
// element['transit_duration'] = 6
|
||
// element['driving_duration'] = 6
|
||
|
||
arr.forEach(key => {
|
||
if (element[key] > 0) {
|
||
const value = element[key]
|
||
valueArr.push({
|
||
text: keyobj[key],
|
||
value,
|
||
duration: calculateDuration(value),
|
||
})
|
||
}
|
||
})
|
||
|
||
element['distanceArr'] = valueArr.sort((a, b) => Number(a.value) - Number(b.value))
|
||
|
||
if (element.sid == sid) pitch = element;
|
||
});
|
||
|
||
if (pitch == null) pitch = distance[0];
|
||
|
||
console.log("distance",distance);
|
||
|
||
|
||
distanceList.value = distance;
|
||
distancePitch.value = pitch;
|
||
});
|
||
};
|
||
|
||
const selectSchoolRef = ref(null);
|
||
|
||
const openSelectSchool = () => {
|
||
isSelectSchool.value = true;
|
||
|
||
nextTick(() => {
|
||
return;
|
||
const item = selectSchoolRef.value.querySelector(`.item${distancePitch.value.sid}`);
|
||
if (!item) return;
|
||
selectSchoolRef.value.scrollTo({ top: item.offsetTop - 20, behavior: "smooth" });
|
||
});
|
||
};
|
||
|
||
const selectSchool = (sid) => {
|
||
let list = distanceList.value;
|
||
distancePitch.value = list.find((item) => item.sid == sid);
|
||
isSelectSchool.value = false;
|
||
|
||
// 修改本地存储
|
||
let pitchValue = localStorage.getItem("apartmentPitchValue");
|
||
if (pitchValue) {
|
||
pitchValue = JSON.parse(pitchValue);
|
||
pitchValue.school = sid;
|
||
localStorage.setItem("apartmentPitchValue", JSON.stringify(pitchValue));
|
||
}
|
||
};
|
||
|
||
const openMap = () => {
|
||
viewMapRef.value.showPop();
|
||
isSelectSchool.value = false;
|
||
};
|
||
|
||
const roomCollect = (id, index) => {
|
||
proxy.$post("https://api.gter.net/v1/apartment/roomCollection", { id }).then((res) => {
|
||
if (res.code != 200) return;
|
||
const data = res.data;
|
||
ElMessage.success(res.message);
|
||
roomList.value[index].iscollection = data.status || 0;
|
||
});
|
||
};
|
||
|
||
let isInspectPop = ref(false);
|
||
let spotObj = ref({});
|
||
let spotSum = ref(0);
|
||
let returnSum = ref(0);
|
||
let remarkList = ref([]);
|
||
let remarkTypeid = ref(0); // 0 全部 1 考察 2 回访
|
||
|
||
const getComment = () => {
|
||
proxy
|
||
.$post("https://api.gter.net/v1/apartment/comment", { token })
|
||
.then((res) => {
|
||
if (res.code != 200) return;
|
||
let data = res.data || [];
|
||
let spot = null; // 实地考察
|
||
let sSum = 0;
|
||
let rSum = 0;
|
||
data.forEach((element) => {
|
||
element.date = formatDate(element.created_at);
|
||
|
||
// 合并视频和图片资源
|
||
element.sources = [
|
||
...(element.attachment.videos || []).map((video) => ({
|
||
type: "videos",
|
||
thumbnail: video.cover,
|
||
poster: video.cover,
|
||
videourl: video.url,
|
||
})),
|
||
...(element.attachment.images || []).map((image) => ({
|
||
type: "attachment",
|
||
imageurl: image.url,
|
||
thumbnail: image.cover,
|
||
})),
|
||
];
|
||
|
||
// 分类统计
|
||
element.typeid === 1 ? ((spot = element), sSum++) : rSum++;
|
||
});
|
||
|
||
spotObj.value = spot;
|
||
remarkList.value = data;
|
||
spotSum.value = sSum;
|
||
returnSum.value = rSum;
|
||
|
||
nextTick(() => {
|
||
handleNavData();
|
||
initNavTab();
|
||
});
|
||
})
|
||
.catch((err) => {
|
||
initNavTab();
|
||
});
|
||
};
|
||
|
||
const formatDate = (dateStr) => {
|
||
const date = new Date(dateStr);
|
||
const year = date.getFullYear();
|
||
const month = date.getMonth() + 1; // 月份从 0 开始
|
||
const day = date.getDate();
|
||
|
||
// 移除前导零(如果需要)
|
||
return `${year}.${month}.${day}`;
|
||
};
|
||
|
||
const openInspectPop = () => {
|
||
isInspectPop.value = true;
|
||
};
|
||
|
||
const previewImg = (index, i) => {
|
||
const list = remarkList.value || [];
|
||
// const url = e.currentTarget.dataset.url;
|
||
|
||
// if (url) {
|
||
// list.forEach((element, indexi) => {
|
||
// (element.sources || []).forEach((element, indexii) => {
|
||
// if (url == element.poster) {
|
||
// index = indexi;
|
||
// i = indexii;
|
||
// }
|
||
// });
|
||
// });
|
||
// }
|
||
|
||
const sources = list[index].sources || [];
|
||
cloaseImageShow(sources, i, "inspect");
|
||
};
|
||
|
||
// 切换点评
|
||
const cutRemarkType = (value) => (remarkTypeid.value = value);
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
/deep/ .returnTop {
|
||
bottom: 88px;
|
||
}
|
||
|
||
/deep/ body {
|
||
padding-bottom: 70px;
|
||
}
|
||
|
||
// 引入公共样式
|
||
@import "@/assets/styles/apartmentDetail.less";
|
||
</style>
|
||
<style lang="less">
|
||
.dis-f {
|
||
display: flex;
|
||
}
|
||
|
||
.jus-x {
|
||
justify-content: center;
|
||
}
|
||
|
||
.jus-sp {
|
||
justify-content: space-around;
|
||
}
|
||
|
||
.al-item {
|
||
align-items: center;
|
||
}
|
||
|
||
.pos-r {
|
||
position: relative;
|
||
}
|
||
|
||
.message-info {
|
||
background: #000000;
|
||
border-color: #000000;
|
||
color: #fff;
|
||
|
||
.el-message__content {
|
||
color: #fff;
|
||
}
|
||
|
||
.el-icon {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.annex-school-box {
|
||
margin: 20px 30px 0;
|
||
cursor: pointer;
|
||
|
||
.annex-left {
|
||
width: 100%;
|
||
height: 101px;
|
||
border: 1px solid #f2f2f2;
|
||
border-radius: 12px 0 0 12px;
|
||
position: relative;
|
||
z-index: 1;
|
||
|
||
.annex-school-item {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
|
||
.distance-item-value {
|
||
height: 24px;
|
||
padding: 0 8px;
|
||
background-color: rgba(246, 246, 246, 1);
|
||
border-radius: 29px;
|
||
width: fit-content;
|
||
|
||
&.special {
|
||
background: linear-gradient(to right, rgba(255, 255, 255, 0.8) -14%, rgba(80, 227, 194, 0.8) 100%);
|
||
}
|
||
|
||
.mileage {
|
||
font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif;
|
||
font-weight: 650;
|
||
font-size: 14px;
|
||
color: #000000;
|
||
margin-right: 6px;
|
||
}
|
||
|
||
.tool-icon {
|
||
width: 14px;
|
||
height: 14px;
|
||
margin-right: 3px;
|
||
}
|
||
|
||
.tool-time {
|
||
font-size: 13px;
|
||
color: #333333;
|
||
}
|
||
}
|
||
}
|
||
|
||
.marker-icon {
|
||
margin: 9px 0 12px;
|
||
}
|
||
|
||
.line-img {
|
||
height: 2px;
|
||
width: 724px;
|
||
background-image: linear-gradient(to right, #d7d7d7 0%, #d7d7d7 50%, transparent 0%);
|
||
background-size: 4px 2px;
|
||
background-repeat: repeat-x;
|
||
position: absolute;
|
||
z-index: -1;
|
||
}
|
||
}
|
||
|
||
.annex-btn {
|
||
width: 90px;
|
||
height: 101px;
|
||
font-size: 14px;
|
||
color: #000000;
|
||
border-radius: 0 12px 12px 0;
|
||
position: relative;
|
||
z-index: 1;
|
||
|
||
.annex-btn-bj {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: -1;
|
||
}
|
||
|
||
.annex-btn-icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-left: 10px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.distance-info-box {
|
||
.title-box {
|
||
font-weight: 650;
|
||
font-size: 20px;
|
||
color: #000000;
|
||
|
||
height: 70px;
|
||
border-bottom: 1px solid #ebebeb;
|
||
border-radius: 16px 16px 0 0;
|
||
|
||
.distance-arrow {
|
||
width: 24px;
|
||
height: 24px;
|
||
margin: 0 28px;
|
||
}
|
||
|
||
.close-icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
position: absolute;
|
||
top: 20px;
|
||
right: 20px;
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
|
||
.distance-info-data {
|
||
.distance-info-left {
|
||
width: 70px;
|
||
flex-direction: column;
|
||
border-right: 1px solid #ebebeb;
|
||
box-sizing: content-box;
|
||
|
||
.distance-info-left-item {
|
||
width: 100%;
|
||
height: 50px;
|
||
font-size: 14px;
|
||
color: #555555;
|
||
cursor: pointer;
|
||
|
||
&.pitch {
|
||
font-weight: 650;
|
||
color: #000000;
|
||
background: linear-gradient(to right, rgba(255, 255, 255, 0.8) -14%, rgba(80, 227, 194, 0.8) 100%);
|
||
}
|
||
|
||
&:last-of-type {
|
||
border-radius: 0 0 0 10px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.distance-info-right {
|
||
padding: 30px 40px;
|
||
|
||
.distance-header-box {
|
||
color: #333333;
|
||
font-weight: 650;
|
||
font-size: 16px;
|
||
margin-bottom: 30px;
|
||
justify-content: space-between;
|
||
|
||
.distance-header-icon {
|
||
width: 30px;
|
||
height: 30px;
|
||
background-color: #fddf6d;
|
||
border-radius: 50%;
|
||
margin-right: 10px;
|
||
|
||
.distance-header-img {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
}
|
||
|
||
.distance-header-hint {
|
||
color: #a09e9e;
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
}
|
||
}
|
||
|
||
.academy-school-item {
|
||
background-color: rgba(246, 246, 246, 1);
|
||
border-radius: 12px;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.academy-school-item-header {
|
||
font-size: 16px;
|
||
width: 670px;
|
||
height: 65px;
|
||
justify-content: space-between;
|
||
padding-left: 22px;
|
||
padding-right: 20px;
|
||
position: relative;
|
||
}
|
||
|
||
.academy-school-item-header .arrow-green {
|
||
width: 7px;
|
||
height: 12px;
|
||
position: absolute;
|
||
left: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
}
|
||
|
||
.academy-school-item-name {
|
||
font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif;
|
||
font-weight: 650;
|
||
color: #000000;
|
||
}
|
||
|
||
.academy-school-item-number {
|
||
color: rgb(51, 51, 51);
|
||
margin-left: 4px;
|
||
font-weight: 400;
|
||
font-family: "ArialMT", "Arial", sans-serif;
|
||
}
|
||
|
||
.academy-school-item-icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-right: 6px;
|
||
}
|
||
|
||
.academy-school-item-time {
|
||
color: #000;
|
||
font-weight: 650;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.academy-school-item-journey {
|
||
border-top: 1px solid #ebebeb;
|
||
padding-top: 22px;
|
||
padding-left: 22px;
|
||
padding-bottom: 30px;
|
||
position: relative;
|
||
}
|
||
|
||
.journey-item {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.journey-item:not(:last-of-type) {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.academy-school-item-journey::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 26.4px;
|
||
width: 1px;
|
||
height: 100%;
|
||
display: block;
|
||
background-image: linear-gradient(to bottom, #aaaaaa 50%, transparent 50%);
|
||
background-size: 1px 4px;
|
||
/* 控制虚线的宽度和间距 */
|
||
}
|
||
|
||
.journey-item:first-of-type::after {
|
||
content: "";
|
||
display: block;
|
||
position: absolute;
|
||
top: -22px;
|
||
left: 0;
|
||
width: 9px;
|
||
height: calc(50% + 22px);
|
||
background-color: rgba(246, 246, 246, 1);
|
||
}
|
||
|
||
.journey-item:last-of-type::after {
|
||
content: "";
|
||
display: block;
|
||
position: absolute;
|
||
bottom: -30px;
|
||
left: 0;
|
||
width: 9px;
|
||
height: calc(50% + 30px);
|
||
background-color: rgba(246, 246, 246, 1);
|
||
}
|
||
|
||
.journey-item .circle {
|
||
width: 9px;
|
||
height: 9px;
|
||
border-radius: 50%;
|
||
background-color: #f6f6f6;
|
||
border: 1px solid #797979;
|
||
box-sizing: border-box;
|
||
margin-right: 20px;
|
||
z-index: 1;
|
||
}
|
||
|
||
.journey-item .journey-value {
|
||
color: #333;
|
||
font-size: 13px;
|
||
padding-right: 20px;
|
||
}
|
||
|
||
.journey-item .journey-value.subway {
|
||
color: #aaaaaa;
|
||
}
|
||
|
||
.journey-item .journey-value.subway .subway-name {
|
||
padding: 3.5px 11px;
|
||
background-color: rgba(51, 51, 51, 1);
|
||
border-radius: 10px;
|
||
color: #fff;
|
||
margin-right: 10px;
|
||
max-width: 570px;
|
||
}
|
||
|
||
.journey-item .journey-value.bus {
|
||
color: #aaaaaa;
|
||
}
|
||
|
||
.journey-item .journey-value.bus .bus-name {
|
||
padding: 3.5px 11px;
|
||
background-color: rgba(80, 227, 194, 0);
|
||
box-sizing: border-box;
|
||
border: 1px solid rgba(51, 51, 51, 1);
|
||
border-radius: 10px;
|
||
margin-right: 10px;
|
||
color: #333333;
|
||
max-width: 570px;
|
||
}
|
||
|
||
.academy-school-hint {
|
||
color: #a09e9e;
|
||
font-size: 13px;
|
||
margin-bottom: 20px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.el-popper.is-light {
|
||
border-radius: 10px !important;
|
||
}
|
||
|
||
.selectSchoolPop {
|
||
border-radius: 16px;
|
||
overflow: hidden;
|
||
|
||
.el-dialog__header {
|
||
display: none;
|
||
}
|
||
|
||
.el-dialog__body {
|
||
padding: 0;
|
||
|
||
.title-box {
|
||
font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif;
|
||
font-weight: 650;
|
||
font-style: normal;
|
||
font-size: 25px;
|
||
line-height: 26px;
|
||
color: #000000;
|
||
text-align: center;
|
||
padding-top: 25px;
|
||
padding-bottom: 16px;
|
||
|
||
.close-icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 10px;
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
|
||
.site {
|
||
height: 35px;
|
||
background-color: rgba(242, 242, 242, 1);
|
||
margin: 0 20px 24px;
|
||
border-radius: 210px;
|
||
padding-left: 10px;
|
||
|
||
.site-img {
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-right: 6px;
|
||
}
|
||
|
||
.site-text {
|
||
font-size: 14px;
|
||
color: #000000;
|
||
}
|
||
|
||
.btn {
|
||
font-size: 13px;
|
||
color: #555555;
|
||
padding: 0 10px;
|
||
height: 100%;
|
||
cursor: pointer;
|
||
|
||
.btn-img {
|
||
width: 6px;
|
||
height: 11px;
|
||
margin-left: 8px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.select-list {
|
||
max-height: 500px;
|
||
min-height: 300px;
|
||
overflow: auto;
|
||
position: relative;
|
||
|
||
.select-item {
|
||
padding: 10px 15px;
|
||
border-top: 1px dotted #d7d7d7;
|
||
cursor: pointer;
|
||
|
||
&.pitch {
|
||
background-color: rgba(245, 244, 249, 1);
|
||
|
||
.select-icon {
|
||
background-color: #fddf6d;
|
||
}
|
||
}
|
||
|
||
&:last-of-type {
|
||
// border-radius: 0 0 16px 16px;
|
||
}
|
||
|
||
.select-icon {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 50%;
|
||
background-color: #f2f2f2;
|
||
align-self: flex-start;
|
||
margin-right: 10px;
|
||
|
||
.select-img {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
}
|
||
|
||
.select-info {
|
||
.select-name {
|
||
font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif;
|
||
font-weight: 650;
|
||
font-style: normal;
|
||
font-size: 16px;
|
||
color: #000000;
|
||
margin-bottom: 7px;
|
||
}
|
||
|
||
.distance {
|
||
font-size: 14px;
|
||
color: #555555;
|
||
// margin-top: 7px;
|
||
padding-bottom: 7px;
|
||
|
||
.abbreviation {
|
||
font-family: "PingFangSC-Semibold", "PingFang SC Semibold", "PingFang SC", sans-serif;
|
||
font-weight: 650;
|
||
font-style: normal;
|
||
color: #000000;
|
||
margin: 0 4px;
|
||
}
|
||
}
|
||
|
||
.vehicle {
|
||
flex-wrap: wrap;
|
||
|
||
.item {
|
||
height: 20px;
|
||
line-height: 20px;
|
||
line-height: 20px;
|
||
background-color: rgba(255, 255, 255, 0);
|
||
border: 1px solid rgba(127, 127, 127, 1);
|
||
border-radius: 30px;
|
||
font-size: 14px;
|
||
color: #333333;
|
||
width: fit-content;
|
||
padding: 0 5px;
|
||
margin-top: 5px;
|
||
margin-right: 10px;
|
||
|
||
.vehicle-icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-right: 5px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.tick {
|
||
width: 20px;
|
||
height: 20px;
|
||
align-self: center;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.inspectPop {
|
||
border-radius: 16px;
|
||
overflow: hidden;
|
||
word-break: break-word;
|
||
|
||
.el-dialog__header {
|
||
display: none;
|
||
}
|
||
|
||
.el-dialog__body {
|
||
padding: 0;
|
||
|
||
.type {
|
||
padding: 20px 20px;
|
||
border-bottom: 1px dotted #d7d7d7;
|
||
|
||
.item {
|
||
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
line-height: 30px;
|
||
border-radius: 12px;
|
||
height: 30px;
|
||
background-color: rgba(235, 235, 235, 1);
|
||
padding: 0 12px;
|
||
margin-right: 15px;
|
||
cursor: pointer;
|
||
|
||
&.pitch {
|
||
background-color: rgba(249, 93, 93, 1);
|
||
color: #ffffff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.list {
|
||
max-height: 600px;
|
||
overflow: auto;
|
||
|
||
.item {
|
||
padding-top: 20px;
|
||
padding-left: 20px;
|
||
|
||
&:not(:last-of-type) {
|
||
border-bottom: 1px #d7d7d7 dotted;
|
||
}
|
||
|
||
.avatar {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 50%;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.remark-content {
|
||
flex-direction: column;
|
||
position: relative;
|
||
|
||
.type {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
font-size: 14px;
|
||
color: #555555;
|
||
height: 23px;
|
||
background: inherit;
|
||
background-color: #f2f2f2;
|
||
border-radius: 78px 0 0 78px;
|
||
padding: 0 6px;
|
||
border: none;
|
||
|
||
.image {
|
||
// width: 24px;
|
||
height: 16px;
|
||
margin-right: 4px;
|
||
}
|
||
}
|
||
|
||
.username {
|
||
// font-size: 24px;
|
||
font-size: 14px;
|
||
// color: #333333;
|
||
// margin-bottom: 4.5px;
|
||
|
||
color: #555;
|
||
margin-right: 10px;
|
||
// cursor: pointer;
|
||
margin-bottom: 4px;
|
||
|
||
.image {
|
||
// width: 72px;
|
||
height: 16px;
|
||
margin-left: 12px;
|
||
}
|
||
|
||
.checked-in {
|
||
height: 20px;
|
||
line-height: 20px;
|
||
background-color: rgba(246, 246, 246, 0);
|
||
border: 1px solid rgba(80, 227, 194, 1);
|
||
border-radius: 45px;
|
||
font-size: 12px;
|
||
color: #50e3c2;
|
||
padding: 0 8px;
|
||
margin-left: 12px;
|
||
}
|
||
}
|
||
|
||
.date {
|
||
color: #a3a3a3;
|
||
font-size: 13px;
|
||
margin-bottom: 3px;
|
||
}
|
||
|
||
.text {
|
||
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
font-size: 14px;
|
||
line-height: 24px;
|
||
white-space: pre-line;
|
||
margin-bottom: 12px;
|
||
margin-right: 13px;
|
||
color: #333333;
|
||
}
|
||
|
||
.media {
|
||
white-space: nowrap;
|
||
overflow: auto;
|
||
width: 512px;
|
||
margin-bottom: 20px;
|
||
|
||
.media-item {
|
||
display: inline-flex;
|
||
margin-right: 8px;
|
||
position: relative;
|
||
cursor: pointer;
|
||
|
||
.media-img {
|
||
// width: 213px;
|
||
width: 105px;
|
||
height: 70px;
|
||
border-radius: 8px;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.media-icon {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 60px;
|
||
height: 60px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|