Files
dvcp_v2_wxcp_app/library/project/saas/AppBuilding/components/searchMap.vue

720 lines
19 KiB
Vue
Raw Normal View History

2022-01-25 16:31:39 +08:00
<template>
<div class="searchMap">
2022-08-09 16:44:56 +08:00
<div class="top">
<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-w.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>
2022-01-25 16:31:39 +08:00
</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>
2022-02-11 14:26:59 +08:00
<p class="address" v-if="detailInfo.community">{{ detailInfo.community.address || '' }}</p>
2022-01-25 16:31:39 +08:00
<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>
2022-02-11 16:57:05 +08:00
<span class="value" v-if="detailInfo.build && detailInfo.build.appGirdInfo">{{ detailInfo.build.appGirdInfo.girdName || '' }}</span>
2022-01-25 16:31:39 +08:00
</div>
<div class="info-flex">
<span class="label">网格管理员</span>
2022-02-11 16:57:05 +08:00
<span class="value" v-if="detailInfo.build.appGirdInfo && detailInfo.build.appGirdInfo.girdMemberNames && detailInfo.build.appGirdInfo.girdMemberNames.length">
<span v-for="(item, index) in detailInfo.build.appGirdInfo.girdMemberNames" :key="index">
<AiOpenData v-if="item" type="userName" :openid="item" style="display:inline-block;" /><span v-if="index<detailInfo.build.appGirdInfo.girdMemberNames.length-1">,</span>
2022-02-11 14:29:52 +08:00
</span>
</span>
2022-01-25 16:31:39 +08:00
</div>
<div class="info-flex">
<span class="label">楼栋长</span>
<span
2022-02-11 14:26:59 +08:00
class="value">{{ detailInfo.build.managerName || '' }}
2022-08-16 15:38:38 +08:00
&nbsp;&nbsp;{{
2022-01-25 16:31:39 +08:00
detailInfo.build.managerPhone || ''
}}
<img :src="$cdn + 'common/phone.png'" alt="" @click="callPhone(detailInfo.build.managerPhone)"
2022-08-16 15:38:38 +08:00
class="phone-icon" v-if="detailInfo.build.managerPhone">
2022-01-25 16:31:39 +08:00
</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>
2022-02-11 14:26:59 +08:00
<span class="value">
<span v-for="(item, index) in building.girdMemberNames" :key="index">
2022-02-11 14:35:18 +08:00
<AiOpenData v-if="item" type="userName" :openid="item" style="display:inline-block;" /><span v-if="index<building.girdMemberNames.length-1">,</span>
2022-02-11 14:26:59 +08:00
</span>
</span>
2022-01-25 16:31:39 +08:00
</div>
<div class="info-flex">
<span class="label">楼栋长</span>
<span
2022-02-11 14:26:59 +08:00
class="value">{{ building.managerName || '' }}
2022-08-16 15:38:38 +08:00
&nbsp;&nbsp;{{ building.managerPhone || '' }}
2022-01-25 16:31:39 +08:00
<img :src="$cdn + 'common/phone.png'" alt="" @click="callPhone(detailInfo.build.managerPhone)"
2022-08-16 15:38:38 +08:00
class="phone-icon" v-if="detailInfo.build.managerPhone">
2022-01-25 16:31:39 +08:00
</span>
</div>
</div>
<div class="popup-btn" @click="toDetail(building.id)">查看楼栋模型</div>
</u-popup>
2022-08-16 10:53:21 +08:00
<u-popup v-model="show" mode="bottom" border-radius="14" height="70%">
<div class="grid-wrapper">
<div class="title">请选择居民</div>
<scroll-view scroll-y="true" class="grid-info">
<div
class="grid-item"
v-for="(item, index) in buildList"
@click="getBuildingInfo(item)"
:key="index">
<image src="./img/user-icon.png" />
<div class="right">
<h3>{{ item.residentName }}</h3>
<p>{{ item.areaName || '' }}{{ item.createAddress }}</p>
</div>
</div>
</scroll-view>
</div>
</u-popup>
2022-01-25 16:31:39 +08:00
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
2022-01-26 12:02:32 +08:00
name:"searchMap",
2022-01-25 16:31:39 +08:00
data() {
return {
ops: {},
lib: null,
map: null,
markerArr: [],
show: false,
value: '',
2022-08-09 16:44:56 +08:00
form: {girdName: '', id: ''},
2022-01-25 16:31:39 +08:00
ClusterBubble: null,
name: '',
buildList: [],
detailInfo: {
house: {},
build: {},
community: {},
gird: {}
},
showPop: false,
retryMapCount: 0,
building: {},
2022-08-16 10:53:21 +08:00
isShowGrid: false,
2022-01-25 16:31:39 +08:00
buildPopup: false
}
},
2022-07-20 12:07:23 +08:00
computed: {...mapState(['user', 'wxwork'])},
2022-01-25 16:31:39 +08:00
mounted() {
this.getCommunityList().then(points => {
this.getMarkerCluster(points)
})
},
onShow() {
document.title = "以房找人"
},
created() {
this.$dict.load("communityBuildingType")
},
methods: {
2022-08-09 16:44:56 +08:00
handleSelectGird(v) {
this.form = v || {}
// this.getGridList(v?.id, true)
},
2022-01-25 16:31:39 +08:00
getCommunityList() {
return this.$http.post('/app/appcommunitybuildinginfo/listByBuilding', null, {
params: {
current: 1,
size: 1000000,
}
}).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) {
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 || {}
2022-02-11 14:26:59 +08:00
this.building.girdMemberNames = this.building.girdMemberNames.split(',')
2022-10-26 14:54:40 +08:00
// if(item.geometries[0].properties.id) {
// this.$http.post(`/app/appcommunitybuildinginfo/queryBuildingInfo?buildingId=${item.geometries[0].properties.id}`).then(res => {
// this.building = res.data
// this.building.girdMemberNames = this.building.girdMemberNames.split(',')
// this.buildPopup = true
// })
// }
2022-01-25 16:31:39 +08:00
})
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 = []
2022-08-16 10:53:21 +08:00
this.$loading()
2022-08-16 13:37:35 +08:00
this.$http.post('/app/appcommunityhouseinfo/queryHouseByNameBySize', null, {
2022-01-25 16:31:39 +08:00
params: {
current: 1,
size: 20,
name: this.name
}
}).then(res => {
if (res.code == 0 && res.data.length) {
this.show = true
this.buildList = res.data
2022-02-11 14:35:18 +08:00
const points = res.data.map(item => {
2022-02-11 14:26:59 +08:00
if(item.lng && item.lat) {
2022-02-11 14:35:18 +08:00
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,
}
2022-01-25 16:31:39 +08:00
}
})
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) {
2022-02-11 16:57:05 +08:00
2022-02-11 14:29:52 +08:00
this.detailInfo = {...res.data}
2022-02-11 16:57:05 +08:00
2022-08-16 10:24:52 +08:00
if(this.detailInfo.build.appGirdInfo && this.detailInfo.build.appGirdInfo.girdMemberNames && this.detailInfo.build.appGirdInfo.girdMemberNames) {
2022-02-11 16:57:05 +08:00
this.detailInfo.build.appGirdInfo.girdMemberNames = this.detailInfo.build.appGirdInfo.girdMemberNames.split(',')
2022-02-11 14:29:52 +08:00
}
2022-02-11 16:57:05 +08:00
this.show = false
this.showPop = true
2022-01-25 16:31:39 +08:00
}
})
},
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;
2022-08-09 16:44:56 +08:00
* {
box-sizing: border-box;
}
2022-08-16 10:53:21 +08:00
.grid-wrapper {
height: 100%;
overflow: hidden;
.title {
height: 80px;
line-height: 80px;
text-align: center;
color: #333;
font-size: 32px;
font-weight: 800;
}
scroll-view {
height: calc(100% - 80px);
}
.grid-item {
display: flex;
align-items: center;
padding: 20px 24px;
color: #333;
font-size: 28px;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-bottom: 1px solid #eee;
image {
width: 50px;
height: 50px;
margin-right: 16px;
}
.right {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
h2 {
margin-bottom: 12px;
color: #333;
font-size: 30px;
font-weight: 600;
}
p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #666;
}
}
&:last-child {
border: none;
}
&:active {
background: #eee;
}
}
}
2022-08-09 16:44:56 +08:00
.top {
display: flex;
2022-01-25 16:31:39 +08:00
position: fixed;
2022-08-09 16:44:56 +08:00
align-items: center;
justify-content: space-between;
2022-08-15 10:28:46 +08:00
top: 96px;
2022-08-09 16:44:56 +08:00
left: 0;
z-index: 1111;
width: 100%;
height: 112px;
padding: 0 32px;
background: #FFF;
2022-01-25 16:31:39 +08:00
box-sizing: border-box;
2022-08-09 16:44:56 +08:00
.gird-content {
display: flex;
align-items: center;
image {
width: 32px;
height: 34px;
margin-right: 16px;
}
.label {
max-width: 120px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #666666;
font-size: 28px;
}
}
.left {
flex: 1;
}
}
.grid-input {
display: flex;
align-items: center;
2022-08-16 10:24:52 +08:00
width: 100%;
2022-08-09 16:44:56 +08:00
height: 64px;
background: #F5F5F5;
border-radius: 32px;
padding: 0 36px;
2022-01-25 16:31:39 +08:00
.search-icon {
2022-08-09 16:44:56 +08:00
width: 32px;
height: 32px;
2022-01-25 16:31:39 +08:00
margin-right: 16px;
}
.input {
2022-08-09 16:44:56 +08:00
flex: 1;
height: 64px;
width: 100%;
2022-01-25 16:31:39 +08:00
font-size: 28px;
color: #666;
}
.back-icon {
width: 16px;
height: 32px;
margin-right: 24px;
vertical-align: super;
}
.clear-btn {
width: 32px;
height: 32px;
}
.del-icon {
width: 32px;
height: 32px;
}
}
.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 {
2022-08-15 10:28:46 +08:00
position: fixed;
top: 96px;
left: 0;
2022-01-25 16:31:39 +08:00
width: 100%;
2022-08-15 10:28:46 +08:00
height: calc(100vh - 96px);
2022-01-25 16:31:39 +08:00
}
.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;
width: fit-content;
2022-08-09 16:44:56 +08:00
padding: 10px 32px;
2022-01-25 16:31:39 +08:00
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>