You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
12 KiB
315 lines
12 KiB
<template>
|
|
<div class="w-full min-h-screen pt-16 pb-7 bg-gradient-to-b from-[#1974ff] to-[#f8faff] to-50%">
|
|
<Crumbs :breadcrumbs="[
|
|
{ title: '看房', path: '/Showings' },
|
|
{ title: '公寓详情', path: '/apartmentDetail', query: { deptId: deptId } },
|
|
{ title: '公寓房型', path: '/roomTypeList', query: { apartmentId: deptId } },
|
|
{ title: '房型详情', path: '' },
|
|
]" :width="1678" />
|
|
<div class="w-[1310px] mx-auto mt-10 bg-white pb-9 px-14 pt-6 rounded relative">
|
|
<div class="title ">
|
|
<h3 class="font-bold text-2xl">房型详情</h3>
|
|
</div>
|
|
<div class="flex">
|
|
<div class="flex-col w-full pt-2 ">
|
|
<div class=" pr-10 w-[592px]">
|
|
<div class=" w-full relative">
|
|
<!-- <div v-if="activeTab === 'video'" class="w-full h-72">
|
|
<video :src="houseDetail.videos[0] ? houseDetail.videos[0].url : ''" controls
|
|
class="w-full h-full object-cover rounded-md" />
|
|
</div> -->
|
|
<el-carousel v-if="activeTab === 'img'" height="290px">
|
|
<el-carousel-item v-for="(img, idx) in houseDetail.images" :key="idx">
|
|
<img :src="img.url" class="w-full h-72 object-cover rounded-md" />
|
|
</el-carousel-item>
|
|
</el-carousel>
|
|
<div v-if="activeTab === 'vr'" class="relative h-[290px]">
|
|
<img class="w-full h-[290px] object-cover rounded-md" :src="houseDetail.coverImg" alt="VR封面图" />
|
|
<a :href="houseDetail.vrUrl" target="_blank">
|
|
<div class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-30 cursor-pointer">
|
|
</div>
|
|
</a>
|
|
</div>
|
|
<div
|
|
class="mt-4 flex justify-center border rounded-full overflow-hidden w-fit absolute bottom-10 left-1/2 -translate-x-1/2">
|
|
<button class="px-4 py-1 text-sm font-medium"
|
|
:class="activeTab === 'vr' ? 'bg-blue-500 text-white' : 'bg-white text-gray-800'"
|
|
@click="activeTab = 'vr'">
|
|
VR
|
|
</button>
|
|
<button class="px-4 py-1 text-sm font-medium"
|
|
:class="activeTab === 'img' ? 'bg-blue-500 text-white' : 'bg-white text-gray-800'"
|
|
@click="activeTab = 'img'">
|
|
图片
|
|
</button>
|
|
<!-- <button class="px-4 py-1 text-sm font-medium"
|
|
:class="activeTab === 'video' ? 'bg-blue-500 text-white' : 'bg-white text-gray-800'"
|
|
@click="activeTab = 'video'">
|
|
视频
|
|
</button> -->
|
|
|
|
</div>
|
|
<div v-if="activeTab === 'vr'" class=" mt-4 flex justify-center border rounded-full overflow-hidden w-fit
|
|
absolute bottom-24 left-1/2 -translate-x-1/2" @click="handleVr">
|
|
<img class="opacity-10" src="@/assets/images/ar.png">
|
|
</div>
|
|
|
|
</div>
|
|
<div class="pt-3">
|
|
<div class="text-xl font-bold ">{{ houseDetail.apartmentName }} I {{ houseDetail.typeName }}</div>
|
|
</div>
|
|
<div class="pt-3 text-base flex">
|
|
<div class=" ">房型:</div>
|
|
<div class=" font-bold text-red-400 ">
|
|
<span class="">{{ houseDetail.roomCount }}</span>室<span>{{ houseDetail.livingRoomCount
|
|
}}</span>厅<span>{{ houseDetail.bathroomCount }}</span>卫
|
|
</div>
|
|
<div class=" pl-7">面积:</div>
|
|
<div class="font-bold text-red-400 ">{{ houseDetail.area }}m²</div>
|
|
</div>
|
|
<el-divider direction="horizontal" />
|
|
<div class="pt-3">
|
|
<div class="text-xl font-bold ">房屋设施</div>
|
|
</div>
|
|
<div class="flex pt-3 flex-wrap gap-2">
|
|
<div v-for="(item, index) in houseDetail.facilityOptions" :key="index">
|
|
<img class="w-33 h-5 pl-7" style="width: 50px; height: 20px;" :src="item.url" />
|
|
<div class="text-center w-20 h-7">{{ item.name }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="w-px bg-gray-200 border-dashed h-auto mx-4"></div>
|
|
<div class="flex-col w-full justify-between pl-10">
|
|
<!-- <div class=" pr-10">
|
|
<div>
|
|
<div class="text-xl font-bold ">入住评价</div>
|
|
</div>
|
|
<div class="max-h-[600px] overflow-y-auto pr-2">
|
|
<div class="items-start gap-4 py-4 border-gray-200 border-dashed"
|
|
:class="{ 'border-b': index !== houseDetail.roomTypes.length - 1 }"
|
|
v-for="(item, index) in houseDetail.roomTypes" :key="index">
|
|
<div class="flex justify-between w-full">
|
|
<div class="flex">
|
|
|
|
<img class="w-16 h-16 object-cover rounded-full" :src="item.coverImg" alt="封面" />
|
|
<div class="flex flex-col pl-3">
|
|
<div class="flex flex-wrap items-center text-sm text-gray-600 mt-2 space-x-3">
|
|
<div>{{ item.roomTypeName }}</div>
|
|
</div>
|
|
<div class="text-xs text-gray-500 mt-2 leading-snug">{{ houseDetail.createTime }}</div>
|
|
</div>
|
|
</div>
|
|
<el-rate disabled v-model="starRating" colors="['#13c2c2']" size="large" />
|
|
</div>
|
|
<div class="flex gap-x-0.5">
|
|
<div v-for="(item, index) in houseDetail.facilityIcon" :key="index" class="flex">
|
|
<img class="w-28" src="../../assets/images/ewm1.png">
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div> -->
|
|
<div class=" pr-10 ">
|
|
<div class="text-xl font-bold">房间详情</div>
|
|
<div class="overflow-y-auto max-h-[600px]">
|
|
<div class="flex items-start gap-4 py-4 border-gray-200 border-dashed"
|
|
:class="{ 'border-b': index !== houseDetail.roomTypes.length - 1 }"
|
|
v-for="(item, index) in houseDetail.roomTypes" :key="index">
|
|
<!-- 封面图 -->
|
|
<img class=" w-44 h-28 object-cover rounded-md" :src="item.images[0].url" alt="封面" />
|
|
|
|
<!-- 文字信息 -->
|
|
<div class="flex flex-col justify-between">
|
|
<div class="text-lg font-bold">{{ item.roomTypeName }}</div>
|
|
<div class="flex flex-wrap items-center text-sm text-gray-600 mt-2 space-x-3">
|
|
<div>{{ item.area }}㎡</div>
|
|
<div>{{ item.roomTypeName }}</div>
|
|
<div>{{ item.hasWindow ? '有窗' : '无窗' }}</div>
|
|
</div>
|
|
<div class="text-xs text-gray-900 mt-2 leading-snug">
|
|
<div :class="item.isExpanded ? '' : 'line-clamp-2'" class="transition-all duration-300">
|
|
{{ item.description }}
|
|
</div>
|
|
<div v-if="item.description && item.description.length > 50"
|
|
class="text-blue-600 cursor-pointer mt-1 hover:text-blue-800 transition-colors"
|
|
@click="toggleDescription(item)">
|
|
查看
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<script setup>
|
|
import { ref } from "vue";
|
|
import { getHouseDetail, getDict, getDeptInfo, getHouseTypeList } from "@/api/index";
|
|
import { useRouter, useRoute } from 'vue-router';
|
|
import { onMounted } from 'vue';
|
|
import AMapLoader from "@amap/amap-jsapi-loader";
|
|
import Crumbs from '@/components/Crumbs.vue';
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const activeTab = ref('vr')
|
|
const deptId = route.query.deptId;
|
|
const houseId = route.query.id;
|
|
const imgList = ref([
|
|
'https://example.com/img1.jpg',
|
|
'https://example.com/img2.jpg',
|
|
'https://example.com/img3.jpg',
|
|
])
|
|
const houseDetail = ref({}); // 存储房屋详情数据
|
|
const residentialDetail = ref({}); // 存储小区详情数据
|
|
const dictList = ref([]); // 存储字典数据
|
|
const deptInfo = ref({}); // 存储部门信息数据
|
|
const getDictTab = ref([])
|
|
const getRoomList = ref([])
|
|
let map = null;
|
|
const starRating = ref(3.7)
|
|
const mapContainer = ref(null);
|
|
const handerReturn = async () => {
|
|
router.go(-1) // 返回上一页
|
|
}
|
|
const handleVr = () => {
|
|
window.open(houseDetail.value.vrUrl, '_blank')
|
|
}
|
|
|
|
// 切换描述展开/收起状态
|
|
const toggleDescription = (item) => {
|
|
item.isExpanded = !item.isExpanded;
|
|
}
|
|
const getHouseType = async () => {
|
|
try {
|
|
console.log(houseId, "sfdjksdlk;");
|
|
const parms = {
|
|
id: houseId
|
|
}
|
|
|
|
const res = await getHouseDetail(parms);
|
|
console.log(res, "sfdjksdlk;");
|
|
houseDetail.value = res.data;
|
|
|
|
// 合并 facilityIcon 和 facilityNames 为数组对象
|
|
if (res.data.facilityIcon && res.data.facilityNames) {
|
|
houseDetail.value.facilityOptions = res.data.facilityIcon.map((icon, index) => ({
|
|
url: icon,
|
|
name: res.data.facilityNames[index] || ''
|
|
}));
|
|
} else {
|
|
houseDetail.value.facilityOptions = [];
|
|
}
|
|
|
|
// 这里可以处理res,比如赋值给响应式变量
|
|
} catch (error) {
|
|
}
|
|
};
|
|
const getRoom = async () => {
|
|
try {
|
|
console.log(houseId, "sfdjksdlk;");
|
|
const parms = {
|
|
apartmentId: deptId
|
|
}
|
|
const res = await getHouseTypeList(parms);
|
|
getRoomList.value = res.data
|
|
} catch (error) {
|
|
}
|
|
};
|
|
const getdeptDetails = async () => {
|
|
try {
|
|
const tagColors = ['primary', 'success', 'info', 'warning', 'danger'];
|
|
const parms = {
|
|
deptId: deptId
|
|
}
|
|
const res = await getDeptInfo(parms);
|
|
console.log(res, getDictTab.value, "sfdjk111sdlk;");
|
|
residentialDetail.value = res.data;
|
|
initMap()
|
|
residentialDetail.value.labels = res.data.labels.map((item, index) => {
|
|
const match = Object.values(getDictTab.value[0]).find(
|
|
item2 => item === item2.dictValue
|
|
);
|
|
return {
|
|
label: item,
|
|
dictLabel: match ? match.dictLabel : '',
|
|
tagType: tagColors[index]
|
|
};
|
|
});
|
|
|
|
console.log(residentialDetail.value, "edwfw");
|
|
|
|
} catch (error) {
|
|
console.error("获取房屋详情失败", error);
|
|
}
|
|
};
|
|
const getDictList = async () => {
|
|
const res = await getDict({ dictType: "apartment_label" });
|
|
getDictTab.value = Object.values(res.rows)
|
|
getHouseType();
|
|
getdeptDetails();
|
|
getRoom();
|
|
try {
|
|
dict.value = res.rows[0];
|
|
|
|
} catch (error) { }
|
|
};
|
|
const initMap = async () => {
|
|
try {
|
|
const AMap = await AMapLoader.load({
|
|
key: import.meta.env.VITE_AMAP_KEY,
|
|
version: "2.0",
|
|
plugins: ['AMap.Geolocation']
|
|
});
|
|
|
|
map = new AMap.Map(mapContainer.value, {
|
|
viewMode: '2D',
|
|
zoom: 13,
|
|
center: [residentialDetail.value.longtitude, residentialDetail.value.latitude],
|
|
});
|
|
const geolocation = new AMap.Geolocation({
|
|
enableHighAccuracy: true,
|
|
timeout: 10000,
|
|
buttonPosition: 'RB',
|
|
buttonOffset: new AMap.Pixel(10, 20),
|
|
zoomToAccuracy: true,
|
|
});
|
|
map.addControl(geolocation);
|
|
geolocation.getCurrentPosition();
|
|
geolocation.on('complete', (result) => {
|
|
console.log('定位成功', result.position);
|
|
map.setCenter(result.position);
|
|
});
|
|
|
|
geolocation.on('error', (error) => {
|
|
console.error('定位失败', error);
|
|
});
|
|
|
|
} catch (err) {
|
|
console.error('地图加载失败', err);
|
|
}
|
|
|
|
|
|
}
|
|
onMounted(() => {
|
|
getDictList();
|
|
|
|
});
|
|
|
|
</script>
|
|
<style scoped>
|
|
.map-container {
|
|
width: 100%;
|
|
|
|
height: 300px;
|
|
}
|
|
</style>
|