gterFang/src/views/apartmentDetail.vue
2024-04-17 18:40:28 +08:00

2414 lines
93 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<page-top-bar></page-top-bar>
<div class="content wid1200">
<div class="header">
<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>
<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">
<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="synopsis wordbreak">{{ info["introduction"] }}</div>
<div class="place flexacenter" v-if="info['address']">
<div class="left flexacenter">
<img class="icon" alt="位置与交通-图标" src="@/assets/img/publicImage/location-icon.png" />
<div class="place-text ellipsis">{{ info["address"] }}</div>
</div>
<div class="right flexacenter" @click="handleClickNav('addressEle')">
位置与交通
<img class="icon" alt="位置与交通-箭头" src="@/assets/img/publicImage/black-arrow.svg" />
</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">
<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">
<div class="details-left flex1" ref="detailsLeft">
<!-- 房间类型 -->
<div class="type-box" v-if="roomList.length !== 0" ref="roomEle">
<div class="type-item flexacenter" v-for="(item, index) in roomList" :key="index">
<!-- <img class="type-icon" alt="房间类型-角图片" v-if="item['status'] == 1" src="@/assets/img/apartmentDetail/apartment-have.svg" /> -->
<!-- <img class="type-icon" v-else src="@/assets/img/apartmentDetail/apartment-not.svg" /> -->
<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="mediaBtnstate[index] == 0" class="arrow" src="@/assets/img/publicImage/gray-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 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/location-icon.png" />
{{ info.location || "位置" }}
</div>
<view-map :latlng="{ latitude: info['coordinate'][0], longitude: info['coordinate'][1] }" :name="info['address']"></view-map>
<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/detail/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/detail/subway-icon.png" />
<div class="tool-time">{{ item.list[0]?.publictransport?.durationText2 || item.list[0]?.durationText2 || "41min" }}</div>
<!-- <div class="tool-time">{{ "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 :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 || "1km" }}</div>
</div>
<div class="academy-school-item-right flexacenter">
<img v-if="item.publictransport" class="academy-school-item-icon" src="@/assets/img/detail/subway-icon.png" mode="widthFix" />
<img v-else class="academy-school-item-icon" src="@/assets/img/detail/walk-icon.png" mode="widthFix" />
<div class="academy-school-item-time">{{ item?.publictransport?.durationText || item.durationText || "1分钟" }}</div>
</div>
<img class="arrow-green" mode="widthFix" 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>
<!-- 交通 -->
<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 special-offer" 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>
<!-- 公寓设施 -->
<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 class="details-right flexacenter">
<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>
<div class="same-brand-list" v-if="dualBrandList.length != 0">
<div class="same-brand-item" v-for="(item, index) in dualBrandList" @click="gobrand(item)" :key="index">
<div class="same-brand-header">
<img class="same-brand-img" v-lazy="item['image']" />
<div class="apartment-name ellipsis">{{ item["title"] }}</div>
<div class="apartment-synopsis ellipsis">{{ item["propaganda"] }}</div>
</div>
<div class="site flexacenter">
<img class="site-icon" src="@/assets/img/publicImage/location-icon.png" />
<div class="site-text ellipsis">{{ item["address"] }}</div>
</div>
<div class="price-box">
<div class="price-item flexacenter" v-for="(it, i) in item['roomlist']" :key="i">
<div class="room-name ellipsis flex1">{{ it["name"] }}</div>
<div class="flexacenter">
<div class="unit">HK$</div>
<div class="quantity">{{ it["price"] }}</div>
/月
</div>
</div>
</div>
<div class="same-brand-quantity flexcenter">
<div class="quantity">{{ item["roomnum"] }}</div>
个房型
<img class="same-brand-quantity-icon" src="@/assets/img/publicImage/black-arrow.svg" />
</div>
</div>
</div>
</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>
</template>
<script setup>
import { ref, onMounted, onUnmounted, toRefs, watch, getCurrentInstance, nextTick } from "vue"
import { ElMessage, valueEquals } 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 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 = "roomEle"
dualBrandList.value = []
contactReservationState.value = false
customerservicelist.value = []
mediaBtnstate.value = {}
slideshowList.value = null
detailsLeft.value = null
token = ""
carouselIndex.value = 0
allCarouselsData.value = []
// mediaBtnstate.value = {}
init()
distanceSchool()
})
let { uniqid } = router.currentRoute.value.query
let pitchSchool = route.query.school || 0
import { copyToClipboard, metersToKilometers, secondsToHoursMinutes } 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
}
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([])
onMounted(() => {
init()
distanceSchool()
})
const init = () => {
proxy.$get("/tenement/pc/api/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"
})
})
roomList.value = data["roomList"]
data["info"]["coordinate"] = data["info"]["coordinate"].split(",").map(item => {
return +item
})
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())
if (data.withsameapartments > 0) dualBrandData()
})
}
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 facilitiesEle = ref(null)
const lifeEle = ref(null)
const companyEle = ref(null)
const eleseEle = ref(null)
let navconfig = [
{
name: "房间类型",
value: "roomEle",
},
{
name: "优惠活动",
value: "specialEle",
},
{
name: "位置与交通",
value: "addressEle",
},
{
name: "房源详情",
value: "messageEle",
},
{
name: "公寓设施",
value: "facilitiesEle",
},
{
name: "生活",
value: "lifeEle",
},
{
name: "品牌介绍",
value: "companyEle",
},
]
let navList = ref([])
let navTab = ref("roomEle")
// 处理 navList 数据
const handleNavData = () => {
navconfig.forEach(element => {
if (eval(element["value"]).value) navList.value.push(element)
})
}
// 处理点击nav 滚动事件
const handleClickNav = value => {
let scrollTop = eval(value).value.offsetTop + 136
window.scrollTo({ top: scrollTop, behavior: "smooth" })
}
let dualBrandList = ref([]) // 同品牌数据
// 同品牌请求数据
const dualBrandData = () => {
proxy.$get("/tenement/pc/api/apartment", { 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)
onMounted(() => {
window.addEventListener("scroll", handleScroll)
})
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll)
})
const gobrand = item => router.push(`/apartmentDetail?uniqid=${item.uniqid}`)
const handleScroll = () => {
if (Math.random() > 0.3) return
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 selectAcademyIndex = index => {
academyPitchIndex.value = index || 0
targetAcademyPitch.value = annexSchoolList.value[academyPitchIndex.value]
}
// 选择附近学校距离的学校下标
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 => {
if (res.code != 200) return
const data = res.data
info.value.iscollect = data.status || 0
ElMessage.success(res.message)
})
}
</script>
<style lang="less" scoped>
/deep/ .returnTop {
bottom: 88px;
}
/deep/ body {
padding-bottom: 70px;
}
.content {
margin: -36px auto 0;
position: relative;
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
.header {
margin-bottom: 20px;
.top {
width: 1200px;
height: 65px;
background: -webkit-linear-gradient(356.899508550192deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
background: -moz-linear-gradient(93.1004914498078deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
background: linear-gradient(93.1004914498078deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
border-radius: 16px 16px 0 0;
padding: 0 30px;
position: relative;
.brand-name {
height: 22px;
background-color: rgba(128, 108, 36, 1);
border-radius: 8px;
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
color: #fdda55;
padding: 0 11px;
margin-top: 12px;
margin-right: 10px;
font-size: 14px;
}
.brand-abstract {
color: #806c24;
font-size: 14px;
padding-top: 13px;
.item {
cursor: pointer;
&:not(:last-of-type):hover {
color: rgb(51, 51, 51);
text-decoration: underline;
}
}
.arrow {
margin: 0 13px;
width: 7px;
height: 10px;
}
}
.arc-bj {
position: absolute;
bottom: 20px;
right: 0;
width: 20px;
z-index: 1;
// height: 20px;
// background-color: #fff;
.arc {
width: 100%;
height: 100%;
background: rgba(204, 253, 191, 1);
border-radius: 0 0 100% 0;
}
}
}
.header-content {
background-color: #fff;
padding: 25px 30px;
margin-top: -20px;
border-radius: 16px 0 16px 16px;
position: relative;
// box-shadow: 0 0 10px rgba(0, 0, 0, 0.118);
// .arc {
// position: absolute;
// width: 12px;
// height: 12px;
// top: -12px;
// right: 0;
// }
.header-left {
width: 511px;
.slideshow {
position: relative;
margin-bottom: 8px;
/deep/ .el-carousel {
.el-carousel__container {
width: 511px;
height: 340px;
}
.el-carousel__item {
width: 511px;
height: 340px;
display: flex;
align-items: center;
border-radius: 5px;
.img {
width: 100%;
object-fit: cover;
height: 340px;
display: block;
cursor: pointer;
}
.video-icon {
}
}
}
.indicate-type {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
height: 24px;
background-color: rgba(255, 255, 255, 1);
border-radius: 36px;
font-size: 16px;
color: #ffffff;
.indicate-item {
height: 100%;
padding: 0 11px;
font-size: 14px;
color: #555555;
line-height: 24px;
cursor: pointer;
&.pitch {
border-radius: 36px;
color: #ffffff;
background-color: rgba(249, 93, 93, 1);
}
}
}
.indicate {
font-size: 13px;
color: #ffffff;
height: 20px;
line-height: 20px;
background-color: rgba(0, 0, 0, 0.494117647058824);
border-radius: 36px;
padding: 0 7px;
position: absolute;
bottom: 10px;
right: 10px;
}
}
.slideshow-across {
width: 511px;
height: 70px;
background-color: rgba(246, 246, 246, 1);
border: 1px solid rgba(235, 235, 235, 1);
border-radius: 4px;
.slideshow-btn {
width: 32px;
height: 100%;
cursor: pointer;
user-select: none;
&.left {
// transform: rotate(180deg);
}
}
.box {
width: 360px;
overflow: auto;
.item {
height: 60px;
margin-right: 6px;
position: relative;
cursor: pointer;
border-radius: 6px;
&::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.501960784313725);
transform: translate(-50%, -50%);
transition: width 0.3s, height 0.3s;
}
&:hover::after {
width: 0;
height: 0;
}
&.pitch {
&::after {
width: 0;
height: 0;
}
}
.video-icon {
width: 44px;
height: 44px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.img {
height: 100%;
border-radius: 6px;
}
}
}
.arrow {
width: 10px;
height: 17px;
}
}
}
.header-right {
margin-left: 59px;
position: relative;
z-index: 1;
.header-bj,
.header-shade {
width: 601px;
height: 338px;
position: absolute;
bottom: -25px;
right: -30px;
z-index: -1;
border-radius: 0 0 16px 0;
}
.tab-box {
flex-wrap: wrap;
margin-bottom: 9px;
.tab-item {
// height: 24px;
background: -webkit-linear-gradient(145.829772035587deg, rgba(224, 240, 255, 1) 0%, rgba(98, 177, 255, 1) 297%);
background: -moz-linear-gradient(-55.8297720355872deg, rgba(224, 240, 255, 1) 0%, rgba(98, 177, 255, 1) 297%);
background: linear-gradient(-55.8297720355872deg, rgba(224, 240, 255, 1) 0%, rgba(98, 177, 255, 1) 297%);
border-radius: 8px;
font-size: 14px;
color: #447eb3;
line-height: 24px;
padding: 0 7px;
margin-bottom: 12px;
margin-right: 10px;
}
}
.apartment-name {
font-size: 28px;
color: #000000;
line-height: 46px;
margin-bottom: 20px;
}
.synopsis {
font-size: 14px;
color: #7f7f7f;
line-height: 24px;
margin-bottom: 20px;
white-space: pre-wrap;
}
.place-text {
}
.place,
.else {
height: 63px;
justify-content: space-between;
border-top: 1px solid #ebebeb;
.left {
color: #333333;
font-size: 14px;
.icon {
width: 18px;
height: 18px;
margin-right: 10px;
}
}
.right {
font-size: 14px;
color: #7f7f7f;
line-height: 24px;
cursor: pointer;
.icon {
width: 6px;
height: 10px;
margin-left: 10px;
}
.quantity {
width: 18px;
height: 18px;
border-radius: 50%;
font-size: 13px;
color: #333333;
background-color: #fdda55;
}
}
}
}
}
}
.operate-box-bj {
position: fixed;
bottom: 0;
z-index: 1002;
min-width: 1200px;
width: 100%;
left: 0;
border: 1px solid rgba(235, 235, 235, 1);
background: #fff;
-moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
-webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
.operate-box {
width: 1200px;
height: 70px;
// background-color: rgba(255, 255, 255, 1);
// border: 1px solid rgba(235, 235, 235, 1);
// border-radius: 16px;
// -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
// -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
// box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
font-size: 14px;
// padding: 0 30px;
// margin-bottom: 20px;
justify-content: space-between;
// position: sticky;
// top: 0px;
.nav-box {
.nav-item {
height: 40px;
background-color: rgba(246, 246, 246, 1);
border-radius: 8px;
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
font-weight: 400;
font-size: 14px;
color: #7f7f7f;
padding: 0 17px;
cursor: pointer;
&:hover {
color: #494848;
}
&.pitch {
background-color: #000;
font-weight: 650;
color: #fff;
}
&:not(:last-of-type) {
margin-right: 10px;
}
}
}
.btn-box {
.btn-item {
width: 100px;
height: 40px;
border-radius: 50px;
cursor: pointer;
&.transmit-btn {
border: 1px solid rgba(235, 235, 235, 1);
color: #333333;
margin-right: 10px;
// position: relative;
.transmit-icon {
width: 20px;
height: 20px;
margin-right: 4px;
}
}
&.consult-btn {
width: 180px;
background: -webkit-linear-gradient(324.854454500294deg, rgba(98, 177, 255, 1) -11%, rgba(128, 255, 255, 1) 135%);
background: -moz-linear-gradient(125.145545499706deg, rgba(98, 177, 255, 1) -11%, rgba(128, 255, 255, 1) 135%);
background: linear-gradient(125.145545499706deg, rgba(98, 177, 255, 1) -11%, rgba(128, 255, 255, 1) 135%);
font-size: 16px;
color: #ffffff;
&:hover {
background: -webkit-linear-gradient(324.854454500294deg, rgba(128, 255, 255, 1) -11%, rgba(98, 177, 255, 1) 135%);
background: -moz-linear-gradient(125.145545499706deg, rgba(128, 255, 255, 1) -11%, rgba(98, 177, 255, 1) 135%);
background: linear-gradient(125.145545499706deg, rgba(128, 255, 255, 1) -11%, rgba(98, 177, 255, 1) 135%);
}
}
}
}
}
}
.details-box {
justify-content: space-between;
align-items: flex-start;
.details-left {
.type-box {
border-radius: 16px;
background-color: rgba(255, 255, 255, 1);
width: 876px;
margin-bottom: 20px;
.type-item {
// width: 876px;
// background-color: rgba(255, 255, 255, 1);
// border: 1px solid rgba(235, 235, 235, 1);
// border-radius: 16px;
// -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
// -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
// box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
font-size: 14px;
padding: 30px;
// margin-bottom: 20px;
position: relative;
&:not(:last-of-type) {
border-bottom: 1px solid #ebebeb;
}
.type-icon {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 40px;
transform: rotate(270deg);
}
.type-left {
display: flex;
flex-direction: column;
justify-content: center;
.type-name {
font-weight: 650;
font-size: 18px;
color: #000000;
// margin-bottom: 16px;
}
.type-tags {
margin-top: 11px;
flex-wrap: wrap;
// margin-bottom: 20px;
.tags-item {
height: 24px;
background-color: rgba(242, 242, 242, 1);
border-radius: 4px;
line-height: 26px;
font-size: 14px;
color: #7f7f7f;
margin-top: 5px;
margin-right: 8px;
padding: 0 9px;
&.first {
border: 1px solid rgba(80, 227, 194, 1);
color: #50e3c2;
background-color: #fff;
}
}
}
.media-box {
margin-top: 20px;
.media-list {
max-width: 460px;
overflow: auto;
}
.media-item {
position: relative;
margin-right: 10px;
.media-img {
width: 76px;
height: 80px;
border-radius: 10px;
cursor: pointer;
object-fit: cover;
}
.media-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 53px;
height: 53px;
cursor: pointer;
}
}
.media-btn {
height: 80px;
width: 30px;
cursor: pointer;
user-select: none;
.arrow {
width: 10px;
height: 17px;
}
}
}
}
.type-right {
.price-box {
flex-direction: column;
align-items: flex-end;
margin-right: 20px;
.former {
color: #aaaaaa;
font-size: 14px;
text-decoration: line-through;
text-decoration-color: #797979;
margin-bottom: 3px;
}
.new {
.unit {
font-family: "Arial-Black", "Arial Black", sans-serif;
font-weight: 900;
color: #000000;
font-size: 13px;
}
.cost {
font-family: "Arial-Black", "Arial Black", sans-serif;
font-weight: 900;
font-size: 20px;
color: #f95d5d;
margin: 0 6px;
}
align-items: baseline;
font-size: 14px;
color: #555555;
}
}
.consult-btn {
width: 90px;
height: 36px;
background: -webkit-linear-gradient(321.966692522331deg, rgba(98, 177, 255, 1) -13%, rgba(128, 255, 255, 1) 137%);
background: -moz-linear-gradient(128.033307477669deg, rgba(98, 177, 255, 1) -13%, rgba(128, 255, 255, 1) 137%);
background: linear-gradient(128.033307477669deg, rgba(98, 177, 255, 1) -13%, rgba(128, 255, 255, 1) 137%);
border-radius: 36px;
font-weight: 400;
font-size: 15px;
color: #ffffff;
cursor: pointer;
&:hover {
background: -webkit-linear-gradient(321.966692522331deg, rgba(128, 255, 255, 1) -13%, rgba(98, 177, 255, 1) 137%);
background: -moz-linear-gradient(128.033307477669deg, rgba(128, 255, 255, 1) -13%, rgba(98, 177, 255, 1) 137%);
background: linear-gradient(128.033307477669deg, rgba(128, 255, 255, 1) -13%, rgba(98, 177, 255, 1) 137%);
}
}
.full-occupancy {
width: 90px;
height: 36px;
background-color: rgba(237, 246, 255, 0);
border: 1px solid rgba(215, 215, 215, 1);
border-radius: 36px;
font-weight: 400;
font-size: 15px;
color: #aaaaaa;
}
}
}
}
.item-title {
padding: 0 11px;
height: 26px;
background-color: rgba(51, 51, 51, 1);
border-radius: 8px;
font-size: 14px;
color: #ffffff;
line-height: 26px;
display: inline-block;
}
.details-item {
width: 876px;
background-color: rgba(255, 255, 255, 1);
border: 1px solid rgba(235, 235, 235, 1);
border-radius: 16px;
// -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
// -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
// box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.117647058823529);
font-size: 14px;
margin-bottom: 20px;
&.location .details-header .icon {
width: 20px;
height: 24px;
}
&.apartment-facilities .details-header .icon,
&.special-offer .details-header .icon {
width: 20px;
height: 20px;
}
&.company .details-header .icon,
&.life .details-header .icon {
width: 22px;
height: 22px;
}
.details-header {
height: 82px;
padding: 0 30px;
border-bottom: 1px solid #ebebeb;
font-size: 16px;
color: #000000;
.icon {
width: 20px;
height: 22px;
margin-right: 4px;
}
}
.text {
font-weight: 400;
font-size: 15px;
color: #555555;
line-height: 30px;
padding: 20px 30px;
white-space: pre-line;
word-break: break-word;
}
.traffic-box {
margin-top: 40px;
padding: 0 30px;
.traffic-title {
margin-bottom: 16px;
}
font-weight: 400;
font-size: 15px;
color: #555555;
line-height: 30px;
white-space: pre-line;
padding-bottom: 30px;
}
&.apartment-facilities {
.facilities-box {
padding: 30px;
.facilities-item {
align-items: flex-start;
&:not(:last-of-type) {
margin-bottom: 30px;
}
.facilities-header {
width: 100px;
}
.facilities-list {
flex-wrap: wrap;
.item {
font-size: 16px;
line-height: 26px;
color: #333333;
margin-bottom: 10px;
margin-right: 50px;
.icon {
width: 16px;
height: 16px;
margin-right: 10px;
}
}
}
}
}
}
&.company {
.company-img {
width: 420px;
height: 254px;
margin: 10px auto 0;
}
}
&.hint-box {
color: #7f7f7f;
line-height: 24px;
font-size: 13px;
padding: 30px;
margin-bottom: 100px;
.hint-item {
min-height: 24px;
a {
cursor: pointer;
color: #7f7f7f;
text-decoration: underline;
}
}
}
}
}
.details-right {
width: 304px;
flex-direction: column;
.same-brand-title {
user-select: none;
margin-bottom: 20px;
font-size: 18px;
color: #000000;
background: -webkit-linear-gradient(350.348166533196deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
background: -moz-linear-gradient(99.6518334668042deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
background: linear-gradient(99.6518334668042deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
border-radius: 12px;
width: 304px;
height: 60px;
border: 5px solid #fff;
position: relative;
// box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.11764706);
&::after {
content: "";
position: absolute;
width: 0;
height: 0;
left: 50%;
bottom: -12px;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 8px solid #fff;
}
.same-brand-icon {
width: 24px;
height: 24px;
margin-right: 4px;
}
}
.same-brand-list {
.same-brand-item {
width: 304px;
background-color: rgba(255, 255, 255, 1);
border-radius: 17px;
// -moz-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.156862745098039);
// -webkit-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.156862745098039);
// box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.156862745098039);
padding: 8px 0;
margin-bottom: 20px;
cursor: pointer;
&:hover {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.25686275);
}
.same-brand-header {
width: 288px;
height: 192px;
overflow: hidden;
border-radius: 17px;
margin: 0 auto 20px;
position: relative;
.same-brand-img {
width: 288px;
height: 192px;
object-fit: none;
}
.apartment-name {
font-weight: 650;
font-style: normal;
font-size: 16px;
color: #000000;
padding: 0 15px;
height: 32px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(255, 255, 255, 0.7);
padding: 0 15px;
border-radius: 40px;
width: max-content;
line-height: 30px;
max-width: 100%;
}
.apartment-synopsis {
width: 100%;
height: 32px;
line-height: 32px;
background-color: rgba(0, 0, 0, 0.63921568627451);
border-radius: 0 0 10px 10px;
position: absolute;
bottom: 0;
font-size: 13px;
color: #d7d7d7;
padding: 0 10px;
}
}
.site {
margin: 0 20px 20px;
color: #555555;
font-size: 14px;
.site-icon {
width: 18px;
height: 18px;
margin-right: 4px;
}
}
.price-box {
font-size: 14px;
color: #555555;
margin: 0 20px 31px;
.price-item {
justify-content: space-between;
height: 50px;
&:not(:last-of-type) {
border-bottom: 1px solid #ebebeb;
}
}
.room-name {
font-size: 15px;
color: #000000;
padding-right: 5px;
}
.unit {
font-family: "Arial-Black", "Arial Black", sans-serif;
font-weight: 900;
color: #000000;
font-size: 13px;
}
.quantity {
font-family: "Arial-Black", "Arial Black", sans-serif;
font-weight: 900;
font-size: 18px;
color: #f95d5d;
margin: 0 5px;
}
}
.same-brand-quantity {
font-size: 14px;
color: #555555;
margin: 21px auto;
.quantity {
font-weight: 650;
font-size: 14px;
color: #000000;
line-height: 18px;
height: 18px;
background-color: #fddf6d;
border-radius: 9px;
padding: 0 8px;
margin: 0 8px;
}
.same-brand-quantity-icon {
width: 7px;
height: 12px;
margin-left: 8px;
}
}
}
}
}
}
}
.add-customer-mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.7);
z-index: 1002;
.add-customer-box {
width: 460px;
height: 460px;
background: -webkit-linear-gradient(315deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
background: -moz-linear-gradient(135deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
background: linear-gradient(135deg, rgba(253, 218, 85, 1) 0%, rgba(229, 215, 190, 1) 50%, rgba(203, 254, 191, 1) 100%);
// border: 1px solid rgba(230, 221, 185, 1);
-moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.235294117647059);
-webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.235294117647059);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.235294117647059);
position: relative;
&.two {
width: 799px;
height: 460px;
.add-customer-violet {
display: none;
&.violet2 {
display: block;
}
}
.add-customer-interior {
width: 700px;
.title {
width: 189px;
height: 31px;
}
.add-customer-interior-bj {
display: none;
&.bj2 {
display: block;
}
}
}
}
.close {
position: absolute;
top: 16px;
right: 16px;
width: 16px;
height: 16px;
cursor: pointer;
}
.add-customer-violet {
position: absolute;
bottom: 0;
left: 0;
top: 0;
right: 0;
width: 421px;
height: 460px;
&.violet2 {
width: 579px;
height: 460px;
display: none;
}
}
.add-customer-interior {
width: 368px;
height: 368px;
position: relative;
z-index: 1;
flex-direction: column;
align-items: center;
padding-top: 35px;
.add-customer-interior-bj {
position: absolute;
top: 0;
left: 0;
z-index: -1;
&.bj2 {
display: none;
}
}
.title {
width: 159px;
height: 26px;
margin-bottom: 35px;
}
.QR-code-list {
.QR-code-item {
&:not(:last-child) {
margin-right: 160px;
}
}
}
.QR-code-box {
margin-bottom: 17px;
padding: 15px;
position: relative;
&::after {
width: 15px;
height: 5px;
}
&::before {
width: 5px;
height: 15px;
}
&::before,
&::after {
content: "";
background-color: rgba(255, 214, 73, 1);
border-radius: 11px;
position: absolute;
top: 0;
left: 0;
}
.top-right-corner {
&::after {
width: 15px;
height: 5px;
}
&::before {
width: 5px;
height: 15px;
}
&::before,
&::after {
content: "";
background-color: rgba(255, 214, 73, 1);
border-radius: 11px;
position: absolute;
top: 0;
right: 0;
}
}
.bottom-left-corner {
&::after {
width: 15px;
height: 5px;
}
&::before {
width: 5px;
height: 15px;
}
&::before,
&::after {
content: "";
background-color: rgba(255, 214, 73, 1);
border-radius: 11px;
position: absolute;
bottom: 0;
left: 0;
}
}
.bottom-right-corner {
&::after {
width: 15px;
height: 5px;
}
&::before {
width: 5px;
height: 15px;
}
&::before,
&::after {
content: "";
background-color: rgba(255, 214, 73, 1);
border-radius: 11px;
position: absolute;
bottom: 0;
right: 0;
}
}
.QR-code-chunk {
width: 130px;
height: 130px;
background-color: rgba(255, 255, 255, 1);
border-radius: 15px;
-moz-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.12156862745098);
-webkit-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.12156862745098);
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.12156862745098);
.QR-code-img {
width: 110px;
height: 110px;
}
}
}
.name {
margin-bottom: 6px;
}
.name,
.hint {
color: #555555;
font-size: 14px;
}
}
}
}
a:-webkit-any-link {
color: #806c24;
}
</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;
}
.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;
}
.academy-school-hint {
color: #a09e9e;
font-size: 13px;
margin-bottom: 20px;
}
}
}
}
.el-popper.is-light {
border-radius: 10px !important;
}
</style>