Files
dvcp_v2_wxcp_app/src/apps/AppBuilding/components/searchMap.vue
2021-12-27 10:07:15 +08:00

598 lines
16 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="searchMap">
<div class="grid-input">
<img src="./img/back-icon.png" alt="" class="back-icon" v-if="name && show" @click="show=false">
<img src="./img/search-icon.png" alt="" class="search-icon" v-else>
<input type="text" class="input" placeholder="请输入姓名、房屋信息" v-model="name" maxlength="10" confirm-type="search"
@confirm="search"/>
<div class="clear-btn">
<img src="./img/del-icon.png" alt="" class="del-icon" v-if="name" @click="clear">
</div>
<span class="search-btn" @click="search">搜索</span>
</div>
<div class="search-list" v-if="show">
<div class="title border">
<img src="./img/search-icon.png" alt="" class="search-icon">{{ name }}
</div>
<div class="item border" v-for="(item, index) in buildList" :key="index" @click="getBuildingInfo(item)">
<img src="./img/user-icon.png" alt="" class="search-icon user-icon">
<div class="item-content">
<h3>{{ item.residentName }}</h3>
<p>{{ item.areaName || '' }}{{ item.createAddress }}</p>
</div>
</div>
</div>
<div class="build-btn" @click="toList()">
<img src="./img/build-icon.png" alt=""> 楼栋<br/>列表
</div>
<div class="map-content">
<AiTMap :map.sync="map" :lib.sync="lib" :ops="ops" :libraries="['service', 'tools']"/>
</div>
<u-popup v-model="showPop" mode="bottom" border-radius="14">
<div class="popup">
<div class="bg"></div>
<div class="title">{{ detailInfo.house.createAddress || '' }}</div>
<p class="address">{{ detailInfo.community.address || '' }}</p>
<div class="info-flex">
<span class="label">所属社区</span>
<span class="value">{{ detailInfo.build.areaName }}</span>
</div>
<div class="info-flex">
<span class="label">所属小区</span>
<span class="value">{{ detailInfo.build.communityName }}</span>
</div>
<div class="info-flex">
<span class="label">房屋类型</span>
<span class="value">{{ $dict.getLabel('communityBuildingType', detailInfo.house.buildingType) }}</span>
</div>
<div class="info-flex">
<span class="label">所属网格</span>
<span class="value">{{ detailInfo.gird.girdName || '' }}</span>
</div>
<div class="info-flex">
<span class="label">网格管理员</span>
<span class="value">{{ detailInfo.gird.girdMemberNames || '' }}</span>
</div>
<div class="info-flex">
<span class="label">楼栋长</span>
<span
class="value">{{ detailInfo.build.managerName || '' }}&nbsp;&nbsp;{{
detailInfo.build.managerPhone || ''
}}
<img :src="$cdn + 'common/phone.png'" alt="" @click="callPhone(detailInfo.build.managerPhone)"
class="phone-icon" v-if="detailInfo.build.managerPhone">
</span>
</div>
</div>
<div class="popup-btn" @click="toDetail(detailInfo.build.id)">查看楼栋模型</div>
</u-popup>
<u-popup v-model="buildPopup" mode="bottom" border-radius="14">
<div class="popup">
<div class="bg"/>
<div class="title">{{ building.createAddress || '' }}</div>
<div class="info-flex">
<span class="label">所属社区</span>
<span class="value">{{ building.areaName }}</span>
</div>
<div class="info-flex">
<span class="label">所属小区</span>
<span class="value">{{ building.communityName }}</span>
</div>
<div class="info-flex">
<span class="label">房屋类型</span>
<span class="value">{{ $dict.getLabel('communityBuildingType', building.buildingType) }}</span>
</div>
<div class="info-flex">
<span class="label">所属网格</span>
<span class="value" v-text="building.girdName||''"/>
</div>
<div class="info-flex">
<span class="label">网格管理员</span>
<span class="value" v-text="building.girdMemberNames||''"/>
</div>
<div class="info-flex">
<span class="label">楼栋长</span>
<span
class="value">{{ building.managerName || '' }}&nbsp;&nbsp;{{ building.managerPhone || '' }}
<img :src="$cdn + 'common/phone.png'" alt="" @click="callPhone(detailInfo.build.managerPhone)"
class="phone-icon" v-if="detailInfo.build.managerPhone">
</span>
</div>
</div>
<div class="popup-btn" @click="toDetail(building.id)">查看楼栋模型</div>
</u-popup>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
data() {
return {
ops: {},
lib: null,
map: null,
markerArr: [],
show: false,
value: '',
ClusterBubble: null,
name: '',
buildList: [],
detailInfo: {
house: {},
build: {},
community: {},
gird: {}
},
showPop: false,
retryMapCount: 0,
building: {},
buildPopup: false
}
},
computed: {...mapState(['user', 'config'])},
mounted() {
this.getCommunityList().then(points => {
this.getMarkerCluster(points)
})
},
onShow() {
document.title = "以房找人"
},
created() {
this.$dict.load("communityBuildingType")
},
methods: {
getCommunityList() {
return this.$http.post('/app/appcommunitybuildinginfo/listByBuilding', null, {
params: {
current: 1,
size: 1000000,
areaId: this.user.areaId
}
}).then(res => {
if (res?.data) {
this.buildList = res.data
return res.data.map(item => {
return {
...item,
lnglat: [item.lng, item.lat],
buildingNumber: item.name || item.buildingNumber,
communityName: item.name || item.communityName,
}
})
}
})
},
getMarkerCluster(points, count = 0) {
let {lib: TMap, map} = this
if (map) {
map.setCenter(this.config.latlng)
let MarkerCluster = new TMap.MarkerCluster({
map, gridSize: 60,
enableDefaultStyle: false, // 关闭默认样式
geometries: points?.map(e => ({
position: new TMap.LatLng(e.lat, e.lng),
content: `${e.createAddress} | ${e.houseNum}`,
properties: {...e}
})) || [],
zoomOnClick: true
})
let geometries = [], marker, markers = []
MarkerCluster.on('cluster_changed', () => {
if (markers.length) {
markers.forEach(function (item) {
item.destroy();
})
markers = [];
}
geometries = []
let clusters = MarkerCluster.getClusters()
clusters.forEach((item) => {
if (item.geometries.length > 1) {
//聚合样式
geometries.push({
styleId: 'cluster',
position: item.center,
properties: {...item},
content: item.geometries.length.toString() || "0"
})
} else {
//点标记样式
// 创建气泡DOM元素
class ClusterBubble extends TMap.DOMOverlay {
constructor(options) {
super(options);
}
onInit(options) {
this.content = options.content;
this.position = options.position;
};
onDestroy() {
this.dom.removeEventListener('click', this.onClick);
this.removeAllListeners();
}
createDOM() {
let dom = document.createElement('div');
dom.classList.add('marker');
dom.innerText = this.content;
// 监听点击事件实现zoomOnClick
this.onClick = this.onClick.bind(this);
// pc端注册click事件移动端注册touchend事件
dom.addEventListener('click', this.onClick);
dom.addEventListener('touchend', this.onClick);
return dom;
};
updateDOM() {
if (!this.map) {
return;
}
// 经纬度坐标转容器像素坐标
let pixel = this.map.projectToContainer(this.position);
// 使文本框中心点对齐经纬度坐标点
let left = pixel.getX() - this.dom.clientWidth / 2 + 'px';
let top = pixel.getY() - this.dom.clientHeight / 2 + 'px';
this.dom.style.transform = `translate(${left}, ${top})`;
this.emit('dom_updated');
};
onClick() {
this.emit('click');
}
}
let {content} = item.geometries?.[0] || {},
overlay = new ClusterBubble({map, position: item.center, content})
overlay.on('click', () => {
this.buildPopup = true
this.building = item.geometries?.[0]?.properties || {}
console.log(this.building)
})
markers.push(overlay)
}
});
if (marker) {
marker.setGeometries(geometries)
} else {
marker = new TMap.MultiMarker({
map, enableCollision: true, geometries,
styles: {
cluster: new TMap.MarkerStyle({
width: 48,
height: 48,
anchor: {x: 24, y: 24},
src: this.$cdn + "/map/cluster.png",
color: '#fff',
// direction: 'center',
size: 18
})
},
})
marker.on('click', (e) => {
let {bounds} = e.geometry.properties
map.fitBounds(bounds)
})
}
})
return Promise.resolve()
} else {
if (count < 5) {
setTimeout(() => {
return this.getMarkerCluster(points, ++count)
}, 1000)
} else Promise.reject("加载失败")
}
},
clear() {
this.name = ''
},
search() {
this.buildList = []
this.$http.post('/app/appcommunityhouseinfo/queryHouseByName', null, {
params: {
current: 1,
size: 20,
areaId: this.user.areaId,
name: this.name
}
}).then(res => {
if (res.code == 0 && res.data.length) {
this.show = true
this.buildList = res.data
const points = res.data.map(item => {
return {
lnglat: [item.lng, item.lat],
id: item.id,
corpId: item.corpId,
areaName: item.areaName,
buildingNumber: item.name || item.buildingNumber,
communityName: item.name || item.communityName,
}
})
this.getMarkerCluster(points)
} else {
this.show = false
this.$u.toast('未搜索到结果,请换个关键字重试!')
}
})
},
getBuildingInfo(item) {
this.$http.post(`/app/appcommunityhouseinfo/queryDetailByIdWithBuilding?buildId=${item.buildingId}&houseId=${item.id}`).then(res => {
if (res?.data) {
this.show = false
this.showPop = true
this.detailInfo = res.data
}
})
},
toList() {
uni.navigateTo({url: './list'})
},
callPhone(phone) {
uni.makePhoneCall({phoneNumber: phone})
},
toDetail(id) {
uni.navigateTo({url: `./detail?id=${id}`})
}
}
}
</script>
<style lang="scss" scoped>
.searchMap {
height: 100vh;
.grid-input {
width: calc(100% - 64px);
height: 88px;
background: #FFF;
box-shadow: 0 4px 8px 0 rgba(192, 185, 185, 0.5);
border-radius: 16px;
position: fixed;
top: 24px;
left: 50%;
transform: translateX(-50%);
z-index: 99999;
padding: 16px 20px;
box-sizing: border-box;
.search-icon {
width: 48px;
height: 48px;
margin-right: 16px;
}
.input {
display: inline-block;
padding: 8px 0;
height: 32px;
line-height: 32px;
width: calc(100% - 220px);
font-size: 28px;
font-family: MicrosoftYaHei;
color: #666;
}
.back-icon {
width: 16px;
height: 32px;
margin-right: 24px;
vertical-align: super;
}
.clear-btn {
display: inline-block;
width: 32px;
height: 32px;
margin-right: 30px;
}
.del-icon {
width: 32px;
height: 32px;
vertical-align: super;
}
.search-btn {
display: inline-block;
width: 80px;
height: 32px;
line-height: 32px;
text-align: right;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #1365DD;
border-left: 1px solid #DEDFE0;
vertical-align: top;
margin-top: 12px;
}
}
.search-list {
position: fixed;
width: 100%;
height: calc(100% - 130px);
overflow-y: scroll;
top: 128px;
left: 0;
box-sizing: border-box;
z-index: 99999;
.search-icon {
width: 36px;
height: 36px;
margin-right: 16px;
vertical-align: sub;
}
.title {
height: 82px;
line-height: 82px;
font-size: 26px;
font-family: MicrosoftYaHeiSemibold;
color: #1365DD;
padding-left: 44px;
background-color: #fff;
}
.item {
padding: 22px 44px 24px 44px;
background-color: #fff;
}
.item-content {
display: inline-block;
width: 610px;
color: #333;
h3 {
font-size: 28px;
font-family: MicrosoftYaHeiSemibold;
line-height: 32px;
margin-bottom: 8px;
}
p {
width: 100%;
font-size: 24px;
font-family: MicrosoftYaHei;
line-height: 32px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.user-icon {
vertical-align: top;
}
.border {
border-bottom: 1px solid #DEDFE1;
}
}
.build-btn {
width: 80px;
height: 160px;
background: #FFF;
box-shadow: 0 4px 8px 0 rgba(138, 138, 138, 0.5);
border-radius: 8px;
position: fixed;
bottom: 136px;
right: 24px;
z-index: 99999;
padding: 16px 16px 0;
box-sizing: border-box;
font-size: 24px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #666;
line-height: 30px;
img {
width: 48px;
height: 48px;
margin-bottom: 8px;
}
}
.map-content {
width: 100%;
height: 100%;
}
.popup {
padding: 0 32px 16px;
.bg {
width: 64px;
height: 10px;
background: #CCC;
border-radius: 6px;
margin: 32px 0 32px 344px;
}
.title {
font-size: 36px;
font-family: PingFang-SC-Heavy, PingFang-SC;
font-weight: 800;
color: #333;
line-height: 50px;
margin-bottom: 24px;
}
.info-flex {
padding: 26px 0 30px 0;
width: 100%;
border-bottom: 1px solid #D8DDE6;
line-height: 40px;
font-size: 28px;
.label {
display: inline-block;
width: 160px;
font-weight: 800;
color: #333;
}
.value {
color: #666;
font-size: 26px;
.phone-icon {
width: 40px;
height: 40px;
vertical-align: sub;
margin-left: 16px;
}
}
}
}
.popup-btn {
width: 100%;
font-size: 32px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
height: 112px;
line-height: 112px;
text-align: center;
background: #1365DD;
color: #FFF;
}
::v-deep.marker {
color: #fff;
background: #5088FF;
padding: 0 32px;
width: fit-content;
height: 56px;
border-radius: 52px;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
&:before {
content: " ";
display: block;
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 0;
transform: translate(-50%, 100%);
border: 12px solid transparent;
border-top-color: #5088FF;
}
}
}
</style>