Files
gterFang/src/components/apartment/seachModule.vue
A1300399510 2267894a80 过渡效果
2023-08-09 17:14:06 +08:00

832 lines
28 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>
<div class="dis-f jus-x al-item" style="position: relative;z-index: 333;">
<div class="body-maxWidth" :class="{ 'seachPage': !props.seachPage }">
<div class="s-w-100 seach-box-bg">
<div class="seach-box">
<div class="top-seach dis-f al-item" v-if="props.seachPage">
<div style="position: absolute;left: -8px;top: 20px;">
<div class="location-box dis-f jus-x al-item">
<img src="../../assets/homeImage/addressImg.png" class="img" alt="">
香港
</div>
<div class="triangle"></div>
</div>
<div class="flexacenter">
<el-popover v-model:visible="historyShow" placement="bottom" :width="560" trigger="click"
:show-arrow="false"
popper-style="background: transparent;padding:0;box-shadow: none;border: none;transform: translateX(50px);">
<template #reference>
<el-input class="search-input" v-model="pitchValue['keyword']" placeholder="搜索房源或输入房源ID"
@keyup.enter='handleKeyword(pitchValue["keyword"])' style="height:48px;width:460px;"
maxlength="15"></el-input>
</template>
<div class="dis-f al-item pos-r">
<div class="seach-hiosory-box scrollbar">
<div class="seach-history-info">
<div v-if="historyArr.length != 0" style="margin-bottom: 30px;">
<div class="title">历史搜索</div>
<div class="info-box">
<div :class="flexacenter" v-for="(item, i) in historyArr" :key="i"
class="btn flexacenter" @click="handleKeyword(item)">
<div class="flexflex">{{ item }}</div>
<img class="btn-icon" src="../../assets/homeImage/closeIcon.svg"
@click.stop="deleteSeachVal(i)" alt="">
<img>
</div>
</div>
</div>
<div>
<div class="title">热门推荐</div>
<div class="info-box">
<div v-for="(item, i) in hotArr.data" :key="i" class="btn"
@click="handleKeyword(item)">{{ item }}
</div>
</div>
</div>
</div>
</div>
</div>
</el-popover>
<div class="seach-btn dis-f al-item jus-x"
@click="pitchValue['keyword'] ? handleKeyword(pitchValue['keyword']) : ''">
<img src="../../assets/homeImage/seachImg.svg" class="img" alt="">
搜索
</div>
</div>
<div class="tool-btn dis-f jus-x al-item add-btn" style="position: relative;">
<img src="../../assets/homeImage/addBtn.png" class="img" alt="">
发布房源
<choosing-identity></choosing-identity>
</div>
<el-popover placement="bottom-end" popper-class="consult-popover flexcenter" :width="300"
trigger="hover" :show-arrow="false"
popper-style="background-color:transparent;border: none;box-shadow: none;padding:0;">
<template #reference>
<div class="tool-btn consult-btn flexcenter">
<img class="consult-icon" src="@/assets/img/publicImage/consult-icon.png">
咨询方同学
</div>
</template>
<div class="consult-pop flexacenter">
<div class="consult-title flexacenter">欢迎联系 <b>{{ wechat['nickname'] }}</b> 咨询房源</div>
<div class="consult-QRcode flexcenter">
<img class="consult-QRcode-img" :src="wechat['personalqrcode']" />
</div>
<div class="consult-hint">微信扫码添加好友</div>
<div class="consult-remark flexacenter">备注<b>寄托租房</b></div>
</div>
</el-popover>
</div>
<!-- 展示的 展开和隐藏按钮 -->
<div class="screen-btn flexcenter" v-if="state == 'pack'" @click="state = 'unfold'">
<b>筛选</b>
<div class="screen-btn-text" style="margin-left:0;">学校附近</div> | <div class="screen-btn-text">品牌
</div> | <div class="screen-btn-text">租金</div> | <div class="screen-btn-text">房型</div> | <div
class="screen-btn-text">楼型</div>
<img class="triangle" src="@/assets/img/publicImage/triangle-black.svg" />
</div>
<div class="option-area flexflex" :class="{ 'option-area-unfold': state == 'unfold' }">
<div class="option-left">
<div class="option-item flexflex">
<div class="option-title">学校附近</div>
<div class="option-box flexflex flex1">
<div class="item flexcenter" :class="{ 'pitch': 0 == pitchValue['school'] }"
@click="selectOption('nearSchool', 0)">不限</div>
<div class="item flexcenter" v-for="item in nearSchoolList"
:class="{ 'pitch': item['id'] == pitchValue['school'] }"
@click="selectOption('nearSchool', item.id)">{{ item['name']
}}</div>
</div>
</div>
<div class="option-item flexflex">
<div class="option-title flexacenter">租金</div>
<div class="option-box flexacenter flex1 option-input-box">
<div class="flex1">
<input class="option-input" type="number" v-model="pitchValue['rent_min']"
@blur="rentBlur" @input="rentInput" /><span style="font-size: 18px;">~</span><input class="option-input"
type="number" v-model="pitchValue['rent_max']" @blur="rentBlur"
@input="rentInput" />HK$/
</div>
<div class="eliminate flexcenter" @click="clearingAmount"
v-if="pitchValue['rent_min'] || pitchValue['rent_max']">
<img class="eliminate-icon" src="@/assets/img/publicImage/round-fork.svg">
清除金额
</div>
</div>
</div>
<div class="option-item flexflex">
<div class="option-title">房型</div>
<div class="option-box flexflex flex1">
<div class="item flexcenter" :class="{ 'pitch': 0 == pitchValue['roomtype'] }"
@click="selectOption('roomType', 0)">不限</div>
<div class="item flexcenter" :class="{ 'pitch': item['id'] == pitchValue['roomtype'] }"
v-for="item in roomTypeList" @click="selectOption('roomType', item.id)">{{
item['name'] }}</div>
</div>
</div>
</div>
<div class="option-right">
<div class="option-item flexflex">
<div class="option-title">品牌</div>
<div class="option-box flexflex flex1">
<div class="item flexcenter" :class="{ 'pitch': 0 == pitchValue['companyid'] }"
@click="selectOption('brand', 0)">不限</div>
<div class="item flexcenter" :class="{ 'pitch': item['id'] == pitchValue['companyid'] }"
v-for="item in brandList" @click="selectOption('brand', item.id)">
{{ item['name'] }}</div>
</div>
</div>
<div class="option-item flexflex">
<div class="option-title">楼型</div>
<div class="option-box flexflex flex1">
<div class="item flexcenter" :class="{ 'pitch': 0 == pitchValue['roomlistings'] }"
@click="selectOption('roomlistings', 0)">不限</div>
<div class="item flexcenter"
:class="{ 'pitch': item['id'] == pitchValue['roomlistings'] }"
v-for="item in roomlistingsList" @click="selectOption('roomlistings', item.id)">
{{
item['name'] }}</div>
</div>
</div>
</div>
</div>
<!-- 收起按钮 -->
<div class="pack-up flexcenter" v-if="state == 'unfold'" @click="state = 'pack'">
收起筛选条件<img class="icon" src="@/assets/img/publicImage/triangle-black.svg" />
</div>
<div class="screen-footer flexacenter" v-if="props.seachPage">
<div class="quantity flexacenter">
<b class="b">{{ count }}</b> 个品牌公寓
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, toRefs, watchEffect, reactive, defineProps, nextTick } from 'vue';
import { useStore } from 'vuex';
import store from '../../store/index';
import { useRoute, useRouter } from 'vue-router';
import choosingIdentity from '@/components/edit/choosingIdentity.vue'
const usestore = useStore();
const { wechat } = toRefs(usestore.state);
const router = useRouter()
const route = useRoute()
const props = defineProps({
count: {
type: Number,
default: 0
},
seachPage: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['handleTransfer'])
let state = ref('pack') // 筛选状态 unfold 展开 pack 收起
//搜索框
let historyShow = ref(false);
let setHistoryShow = () => historyShow.value = historyShow.value // 修改历史记录框的显示状态 通过input的 焦点状态判断的
let historyArr = ref([])//历史查找记录
let hotArr = reactive({ data: [] })
//获取历史搜索记录
historyArr.value = JSON.parse(localStorage.getItem('historyArr')) || []
let nearSchoolList = reactive([{ name: "不限", id: 0 }]); //学校附近
let roomTypeList = reactive([]); // 房型
let roomlistingsList = reactive([]); // 楼型
let brandList = reactive([]); // 品牌数据
watchEffect(() => {
nearSchoolList = store.state.apartment.school || []
roomTypeList = store.state.apartment.roomtype || []
roomlistingsList = store.state.apartment.roomlistings || []
brandList = store.state.apartment.brand || []
hotArr.data = store.state.indexData.hotSearcheWords
})
let pitchValue = ref({
companyid: 0,
roomtype: 0,
rent_min: null, // 租金
rent_max: null, // 租金
school: 0,
roomlistings: 0,
keyword: "",
})
if (route.query['companyid']) {
pitchValue.value['companyid'] = route.query['companyid']
state.value = "unfold"
}
// 是否点击里 清除金额按钮 因为输入金额后再点击清除按钮是会先请求有金额的列表
let clearingAmountState = false
// 点击清除金额
const clearingAmount = () => {
clearingAmountState = true
pitchValue.value['rent_min'] = null
pitchValue.value['rent_max'] = null
emit('handleTransfer', pitchValue)
}
// 金额的失去焦点事件
const rentBlur = () => {
setTimeout(() => {
if (!clearingAmountState) emit('handleTransfer', pitchValue)
}, 300)
}
// 搜索框输入中
const rentInput = () => clearingAmountState = false
// 点击历史搜索和热门推荐
const handleKeyword = value => {
router.push(`/seachPage?keyword=${value}`)
if (historyArr.value.indexOf(value) == -1 && value) {
historyArr.value.unshift(value)
storingHistory()
}
}
//搜索数据
let seachList = () => {
if (historyArr.value.indexOf(pitchValue.value['keyword'] && pitchValue.value['keyword']) == -1) {
historyArr.value.unshift(pitchValue.value['keyword'])
storingHistory()
}
historyShow.value = false
emit('handleTransfer', pitchValue)
}
// 存储历史记录 并判断长度
const storingHistory = () => {
if (historyArr.value.length > 10) historyArr.value = historyArr.value.slice(0, 10)
localStorage.setItem('historyArr', JSON.stringify(historyArr.value));
}
// 选择选项
const selectOption = (type, value) => {
switch (type) {
case 'nearSchool':
pitchValue.value['school'] = value
break;
case 'roomType':
pitchValue.value['roomtype'] = value
break;
case 'brand':
pitchValue.value['companyid'] = value
break;
case 'roomlistings':
pitchValue.value['roomlistings'] = value
break;
default:
break;
}
nextTick(() => {
emit('handleTransfer', pitchValue)
})
}
//删除历史记录
let deleteSeachVal = (i) => {
historyArr.value.splice(i, 1)
localStorage.setItem('historyArr', JSON.stringify(historyArr.value));
}
</script>
<style scoped lang="less">
* {
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
}
.dis-f {
display: flex;
}
.jus-x {
justify-content: center;
}
.al-item {
align-items: center;
}
.pos-r {
position: relative;
}
.body-maxWidth {
width: 1200px;
min-width: 1200px;
}
.s-w-100 {
width: 100%;
}
.jus-bet {
justify-content: space-between;
}
.seachPage {
.seach-box-bg {
background-color: none;
box-shadow: none;
padding-top: 0;
.seach-box {
transform: translate(0, 0);
box-shadow: none;
.option-area {
border-top: none;
}
}
}
}
.seach-box-bg {
background: #d7d7d7;
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-top: 20px;
padding-top: 3px;
.seach-box {
background: #FFFFFF;
// transform: translate(0, 3px);
border-radius: 16px;
.top-seach {
padding: 20px;
position: relative;
justify-content: end;
.intermediary-btn {
background: rgba(241, 245, 247, 1);
}
.location-box {
width: 80px;
height: 40px;
background: inherit;
background-color: rgba(68, 68, 68, 1);
border-radius: 8px;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
-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-family: 'PingFangSC-Semibold', 'PingFang SC Semibold', 'PingFang SC', sans-serif;
// font-weight: 650;
font-size: 16px;
color: #FFFFFF;
line-height: 48px;
position: absolute;
z-index: 666;
}
.triangle {
border: 7px solid;
border-color: transparent #000 transparent transparent;
width: 0;
height: 0;
position: absolute;
// bottom: -46px;
// left: -6px;
bottom: -47px;
left: -7px;
}
.seach-btn {
width: 100px;
height: 48px;
background-color: rgba(98, 177, 255, 1);
border-radius: 0 8px 8px 0;
line-height: 48px;
cursor: pointer;
color: #000;
font-size: 16px;
font-weight: 400;
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
&:hover {
opacity: 0.8;
}
}
.img {
width: 20px;
height: 20px;
object-fit: contain;
margin-right: 5px;
}
.tool-btn {
width: 160px;
height: 48px;
border-radius: 8px;
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
font-weight: 400;
font-style: normal;
font-size: 16px;
color: #000000;
line-height: 48px;
cursor: pointer;
&.add-btn {
background: rgba(253, 218, 85, 1);
margin-left: 20px;
&:hover {
background: rgba(253, 218, 85, 0.8);
}
}
&.consult-btn {
background: rgba(144, 216, 72, 1);
margin-left: 20px;
&:hover {
opacity: 0.8;
}
.consult-icon {
width: 22px;
height: 22px;
margin-right: 5px;
}
}
}
}
.seach-info-box {
padding: 20px 10px;
justify-content: space-around;
flex-wrap: wrap;
}
}
}
.search-input {
/deep/ .el-input__wrapper {
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
&:hover {
border-color: #c0c4cc;
}
border-radius: 8px 0 0 8px;
box-shadow: rgba(235, 235, 235, 1);
background-color: rgba(246, 246, 246, 1);
// border: 1px solid rgba(235, 235, 235, 1);
border-right: none;
.el-input__inner {
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
&::placeholder {
color: #7f7f7f;
font-size: 15px;
}
}
}
}
.screen-btn {
font-size: 15px;
color: #d7d7d7;
line-height: 21px;
height: 60px;
font-family: 'PingFangSC-Semibold', 'PingFang SC Semibold', 'PingFang SC', sans-serif;
background-color: rgba(246, 246, 246, 1);
cursor: pointer;
border-top: 1px solid #ebebeb;
b {
color: #000000;
}
.screen-btn-text {
color: #555555;
margin: 0 10px;
}
.triangle {
width: 10px;
height: 6px;
margin-left: 10px;
}
}
.pack-up {
font-size: 14px;
color: #555555;
height: 40px;
background-color: rgba(246, 246, 246, 1);
border-bottom: 1px solid #ebebeb;
cursor: pointer;
user-select: none;
.icon {
width: 13px;
height: 7px;
transform: rotate(180deg);
margin-left: 10px;
}
}
.screen-footer {
justify-content: space-between;
padding: 0 16px;
.quantity {
color: #555555;
font-size: 15px;
height: 72px;
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
.b {
font-weight: 700;
color: #000000;
margin: 0 5px;
}
}
}
.option-area {
flex-wrap: wrap;
overflow: hidden;
height: 0;
transition: height .25s linear 0s;
&.option-area-unfold {
height: 335px;
border-top: 1px solid #ebebeb;
}
.option-left,
.option-right {
width: 600px;
&:not(:last-of-type) {
border-right: 1px #ebebeb dotted;
}
.option-item {
// width: 540px;
padding-top: 24px;
padding-bottom: 20px;
margin: 0 30px 0 20px;
&:not(:last-of-type) {
border-bottom: 1px #ebebeb dotted;
}
.option-title {
font-size: 14px;
color: #B5B5B5;
width: 90px;
line-height: 30px;
}
.option-box {
flex-wrap: wrap;
.item {
padding: 5px 10px;
height: 30px;
display: flex;
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
font-weight: 400;
font-size: 14px;
text-align: center;
line-height: 30px;
border-radius: 10px;
margin-right: 10px;
margin-bottom: 10px;
cursor: pointer;
color: #7F7F7F;
border: 1px solid transparent;
&:hover {
border: 1px solid rgba(235, 235, 235, 1);
}
&.pitch {
color: #50E3C2;
border: 1px solid #50E3C2;
background: #eefcf9;
}
}
&.option-input-box {
font-weight: 400;
font-size: 14px;
color: #555555;
line-height: 20px;
.eliminate {
width: 96px;
height: 30px;
background-color: rgba(246, 246, 246, 1);
border-radius: 50px;
font-size: 14px;
color: #7F7F7F;
cursor: pointer;
.eliminate-icon {
width: 14px;
height: 14px;
margin-right: 3px;
}
}
.option-input {
width: 100px;
height: 40px;
border: 1px solid rgba(179, 179, 179, 1);
border-radius: 10px;
// outline: none;
font-size: 14px;
margin: 0 10px;
padding: 10px;
&:first-of-type {
margin-left: 0;
}
}
}
}
}
}
}
.seach-hiosory-box {
z-index: 99;
overflow: auto;
border-radius: 16px;
-moz-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.0784313725490196);
-webkit-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.0784313725490196);
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.0784313725490196);
background-color: rgba(255, 255, 255, 1);
border: 1px solid rgba(235, 235, 235, 1);
max-height: 450px;
transition: max-height 0.5s ease-in-out;
.seach-history-info {
padding: 20px 25px;
.title {
font-family: 'PingFangSC-Semibold', 'PingFang SC Semibold', 'PingFang SC', sans-serif;
font-weight: 650;
font-style: normal;
font-size: 16px;
color: #000000;
}
.info-box {
display: flex;
flex-wrap: wrap;
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
font-weight: 400;
font-style: normal;
font-size: 15px;
color: #555555;
text-align: left;
.btn {
margin-top: 20px;
padding-right: 30px;
cursor: pointer;
word-break: break-word;
position: relative;
&:hover .btn-icon {
display: block;
}
.btn-icon {
position: absolute;
top: 50%;
right: 16px;
transform: translateY(-50%);
width: 8px;
height: 8px;
margin-left: 6px;
display: none;
}
}
}
}
}
.el-popover.el-popper.consult-popover {
.consult-pop {
width: 300px;
height: 300px;
border-radius: 10px;
padding-top: 45px;
font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif;
-moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.101960784313725);
-webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.101960784313725);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.101960784313725);
background-color: #fff;
flex-direction: column;
.consult-title {
font-size: 15px;
color: #555555;
margin-bottom: 24px;
b {
color: #000;
font-weight: 650;
margin: 0 5px;
}
}
.consult-QRcode {
width: 120px;
height: 120px;
border-radius: 20px;
-moz-box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.101960784313725);
-webkit-box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.101960784313725);
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.101960784313725);
margin-bottom: 20px;
background: #fff;
.consult-QRcode-img {
width: 100px;
height: 100px;
}
}
.consult-hint {
margin-bottom: 6px;
}
.consult-hint,
.consult-remark {
font-size: 13px;
color: #555555;
line-height: 18px;
}
.consult-remark {
b {
font-weight: 650;
color: #000000;
}
}
}
}
</style>