1634 lines
57 KiB
Vue
1634 lines
57 KiB
Vue
|
<template>
|
|||
|
<view>
|
|||
|
<view class="bottom">
|
|||
|
<div class="info" v-if="showInfo">
|
|||
|
<view class="flex-col section_2">
|
|||
|
<view class="justify-between position-relative">
|
|||
|
<view class="flex-row group_5">
|
|||
|
<image @click="toDetil(detailInfo.userId)" :src="$u.http.config.imgUrl + detailInfo.imageUrl"
|
|||
|
class="image_5"/>
|
|||
|
<view class="name-work">
|
|||
|
<view class="flex-row items-center h100">
|
|||
|
<text class="text text_1">{{ detailInfo.name }}</text>
|
|||
|
<text class="text text_3" v-if="careerList[detailInfo.workFieldName]">
|
|||
|
<img :src="careerList[detailInfo.workFieldName].icon"
|
|||
|
alt="">{{ detailInfo.workLableName || detailInfo.workFieldName }}
|
|||
|
</text>
|
|||
|
<text class="text text_3" v-else>
|
|||
|
{{ detailInfo.workLableName }}
|
|||
|
</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="flex-row section_3">
|
|||
|
<image src="/static/common/img/chats.png" class="image_6"/>
|
|||
|
<text class="text text_2" @click="GoChat(detailInfo.userId)">打招呼</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="flex-row tags">
|
|||
|
<u-tag :text="detailInfo.college" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
<u-tag :text="detailInfo.major" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
<u-tag :text="detailInfo.startYear" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
</view>
|
|||
|
<view>
|
|||
|
<text v-if="detailInfo.aiBlurb" class="text AIdescribe">{{ detailInfo.aiBlurb }}</text>
|
|||
|
</view>
|
|||
|
<view class="flex-row group_6">
|
|||
|
<image src="/static/common/img/location.svg" style="width: 32rpx;height: 32rpx;"></image>
|
|||
|
<text class="text text_5">{{
|
|||
|
detailInfo.province +
|
|||
|
" " +
|
|||
|
detailInfo.city +
|
|||
|
" 距你 " +
|
|||
|
(detailInfo.distance > 1000
|
|||
|
? (detailInfo.distance / 1000).toFixed(1) + "KM"
|
|||
|
: detailInfo.distance + "M")
|
|||
|
}}
|
|||
|
</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</div>
|
|||
|
</view>
|
|||
|
<view class="search-box" @click="toSearch">
|
|||
|
|
|||
|
<image
|
|||
|
src="/static/common/img/search.svg"
|
|||
|
style="width: 40rpx; height: 40rpx"
|
|||
|
></image>
|
|||
|
</view>
|
|||
|
<!-- :scale="map.scale" 缩放max:18 min:5-->
|
|||
|
<map
|
|||
|
id="map"
|
|||
|
ref="map"
|
|||
|
:style="'width: 100vw; height: calc(100vh - .5rem );'"
|
|||
|
:scale="mapScale"
|
|||
|
:layer-style="'style1'"
|
|||
|
@regionchange="regionchange"
|
|||
|
@updated="updated"
|
|||
|
:latitude="map.latitude"
|
|||
|
:longitude="map.longitude"
|
|||
|
:markers="covers"
|
|||
|
@callouttap="de"
|
|||
|
@markertap="getUserDetail"
|
|||
|
@click="tap"
|
|||
|
>
|
|||
|
</map>
|
|||
|
<!-- 回到本人定位位置 -->
|
|||
|
<view class="back-to-location" @click="backToLocation"
|
|||
|
v-if="latitude!=vuex_userLocation.latitude||longitude!=vuex_userLocation.longitude">
|
|||
|
<image src="/static/common/img/back-to-location.png" style="width: 120rpx; height: 120rpx"></image>
|
|||
|
</view>
|
|||
|
<u-tabbar
|
|||
|
:list="vuex_tabbar"
|
|||
|
:class="{ phone: vuex_iPhone }"
|
|||
|
:active-color="vuex_tabbar_config.activeColor"
|
|||
|
:inactive-color="vuex_tabbar_config.inactiveColor"
|
|||
|
></u-tabbar>
|
|||
|
<u-toast ref="uToast"/>
|
|||
|
<!-- 弹出列表 -->
|
|||
|
<view class="popup-box" v-if="showPopup" :style="{
|
|||
|
maxHeight: isExpanded,height: isExpanded,
|
|||
|
}">
|
|||
|
<view class="popup-top"
|
|||
|
@click.stop="togglePopup"
|
|||
|
@touchstart.stop.prevent="touchStart"
|
|||
|
@touchmove.stop.prevent="touchMoveFn"
|
|||
|
@touchend.stop.prevent="touchEnd">
|
|||
|
<view class="pop-top"></view>
|
|||
|
<view class="pop-title">附近校友</view>
|
|||
|
</view>
|
|||
|
<view class="content">
|
|||
|
<template v-for="(item, index) in detailInfoList">
|
|||
|
<view
|
|||
|
v-if="item.userId == 0"
|
|||
|
class="info"
|
|||
|
style="
|
|||
|
position: initial;
|
|||
|
transform: initial;
|
|||
|
margin-bottom: 0.1rem;
|
|||
|
"
|
|||
|
:key="index"
|
|||
|
>
|
|||
|
<view class="flex-col section_2">
|
|||
|
<view class="justify-between position-relative">
|
|||
|
<view class="flex-row group_5">
|
|||
|
<image
|
|||
|
:src="$u.http.config.imgUrl + item.imageUrl"
|
|||
|
class="image_5"
|
|||
|
/>
|
|||
|
<view class="name-work">
|
|||
|
<view class="flex-row items-center h100">
|
|||
|
<text class="text text_1">{{ item.name }}</text>
|
|||
|
<text class="text text_3" v-if="careerList[item.workFieldName]">
|
|||
|
<img :src="careerList[item.workFieldName].icon"
|
|||
|
alt="">{{ item.workLableName || item.workFieldName }}
|
|||
|
</text>
|
|||
|
<text class="text text_3" v-else>
|
|||
|
{{ item.workFieldName }}
|
|||
|
</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view v-if="item.college||item.major||item.startYear" class="flex-row tags">
|
|||
|
<u-tag :text="item.college" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
<u-tag :text="item.major" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
<u-tag :text="item.startYear" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
</view>
|
|||
|
<view>
|
|||
|
<text v-if="item.aiBlurb" class="text AIdescribe">{{ item.aiBlurb }}</text>
|
|||
|
</view>
|
|||
|
<view class="flex-row group_6">
|
|||
|
<image
|
|||
|
src="/static/common/img/location.svg"
|
|||
|
style="width: 32rpx; height: 32rpx"
|
|||
|
></image>
|
|||
|
<text class="text text_5"
|
|||
|
>{{
|
|||
|
item.province +
|
|||
|
" " +
|
|||
|
item.city +
|
|||
|
" 距你 " +
|
|||
|
(item.distance > 1000
|
|||
|
? (item.distance / 1000).toFixed(1) + "KM"
|
|||
|
: item.distance + "M")
|
|||
|
}}
|
|||
|
</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view
|
|||
|
v-else
|
|||
|
class="info"
|
|||
|
style="
|
|||
|
position: initial;
|
|||
|
transform: initial;
|
|||
|
margin-bottom: 0.1rem;
|
|||
|
"
|
|||
|
:key="index"
|
|||
|
>
|
|||
|
<view class="flex-col section_2">
|
|||
|
<view class="justify-between position-relative">
|
|||
|
<view class="flex-row group_5">
|
|||
|
<u-avatar
|
|||
|
@click="toDetil(item.userId)"
|
|||
|
size="0.5rem"
|
|||
|
:src="$u.http.config.imgUrl + item.imageUrl"
|
|||
|
class="image_5"
|
|||
|
></u-avatar>
|
|||
|
<view class="name-work">
|
|||
|
<view class="flex-row items-center h100">
|
|||
|
<text class="text text_1">{{ item.name }}</text>
|
|||
|
<text class="text text_3" v-if="careerList[item.workFieldName]">
|
|||
|
<img :src="careerList[item.workFieldName].icon"
|
|||
|
alt="">{{ item.workLableName || item.workFieldName }}
|
|||
|
</text>
|
|||
|
<text class="text text_3" v-else>
|
|||
|
{{ item.workFieldName }}
|
|||
|
</text>
|
|||
|
</view>
|
|||
|
<view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view @click="GoChat(item.userId)" class="flex-row section_3">
|
|||
|
<image src="/static/common/img/chats.png" class="image_6"/>
|
|||
|
<text class="text text_2">打招呼</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="flex-row tags">
|
|||
|
<u-tag :text="item.college" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
<u-tag :text="item.major" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
<u-tag :text="item.startYear" bg-color="#F6F8F9" color="#000000" mode="dark" size="mini"
|
|||
|
type="info"></u-tag>
|
|||
|
</view>
|
|||
|
<view>
|
|||
|
<text v-if="item.aiBlurb" class="text AIdescribe">{{ item.aiBlurb }}</text>
|
|||
|
</view>
|
|||
|
<view class="flex-row group_6">
|
|||
|
<image
|
|||
|
src="/static/common/img/location.svg"
|
|||
|
style="width: 32rpx; height: 32rpx"
|
|||
|
></image>
|
|||
|
<text class="text text_5"
|
|||
|
>{{
|
|||
|
item.province +
|
|||
|
" " +
|
|||
|
item.city +
|
|||
|
" 距你 " +
|
|||
|
(item.distance > 1000
|
|||
|
? (item.distance / 1000).toFixed(1) + "KM"
|
|||
|
: item.distance + "M")
|
|||
|
}}
|
|||
|
</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
// var jweixin = require('./../../../static/common/js/jweixin.js')
|
|||
|
var jweixin = require("jweixin-module");
|
|||
|
var map;
|
|||
|
var qqmapsdk;
|
|||
|
export default {
|
|||
|
data() {
|
|||
|
return {
|
|||
|
latitude: 0, //纬度
|
|||
|
longitude: 0,
|
|||
|
mapScale: 16,
|
|||
|
showInfo: false,
|
|||
|
height: "calc(100vh - .5rem )",
|
|||
|
width: "100vw",
|
|||
|
// showList: true,
|
|||
|
// viewHeight: 0,
|
|||
|
map: {
|
|||
|
scale: 14,
|
|||
|
latitude: 39.909,
|
|||
|
longitude: 116.39742,
|
|||
|
},
|
|||
|
// 标记点
|
|||
|
covers: [],
|
|||
|
pointDataList: "",
|
|||
|
detailInfoList: [],
|
|||
|
// 中心点
|
|||
|
center: {
|
|||
|
userId: 0,
|
|||
|
latitude: 39.909, //纬度
|
|||
|
longitude: 116.39742, //经度
|
|||
|
iconPath: "", //显示的图标
|
|||
|
rotate: 0, // 旋转度数
|
|||
|
width: 50, //宽
|
|||
|
imageUrl: "",
|
|||
|
height: 50, //高
|
|||
|
name: "我",
|
|||
|
province: "",
|
|||
|
city: "",
|
|||
|
distance: "0",
|
|||
|
workFieldName: "",
|
|||
|
title: "我的位置", //标注点名
|
|||
|
alpha: 0.8, //透明度
|
|||
|
},
|
|||
|
|
|||
|
callout: {
|
|||
|
content: '',//String 文本
|
|||
|
color: '',//String 文本颜色
|
|||
|
fontSize: '',// Number 文字大小
|
|||
|
x: 3,// label的坐标,原点是 marker 对应的经纬度
|
|||
|
y: -20,// label的坐标,原点是 marker 对应的经纬度
|
|||
|
borderWidth: 0,//Number边框宽度
|
|||
|
borderColor: '',//String 边框颜色
|
|||
|
borderRadius: 0,//Number callout边框圆角
|
|||
|
bgColor: '',//String 背景色
|
|||
|
padding: '',//Number 文本边缘留白
|
|||
|
display: 'ALWAYS',//String 'BYCLICK':点击显示; 'ALWAYS':常显
|
|||
|
},
|
|||
|
careerList: {
|
|||
|
'生物/制药/化工/医疗': {
|
|||
|
icon: '/static/common/icon/icon-1.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-1.png',
|
|||
|
},
|
|||
|
'政府机构/翻译/其他': {
|
|||
|
icon: '/static/common/icon/icon-2.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-2.png',
|
|||
|
},
|
|||
|
'人事/行政/高级管理': {
|
|||
|
icon: '/static/common/icon/icon-3.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-3.png',
|
|||
|
},
|
|||
|
'设计/市场/媒体/广告': {
|
|||
|
icon: '/static/common/icon/icon-4.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-4.png',
|
|||
|
},
|
|||
|
'闽建筑/房地产': {
|
|||
|
icon: '/static/common/icon/icon-5.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-5.png',
|
|||
|
},
|
|||
|
'计算机/互联网/通信/电子': {
|
|||
|
icon: '/static/common/icon/icon-6.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-6.png',
|
|||
|
},
|
|||
|
'服务业': {
|
|||
|
icon: '/static/common/icon/icon-7.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-7.png',
|
|||
|
},
|
|||
|
'教育/培训': {
|
|||
|
icon: '/static/common/icon/icon-8.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-8.png',
|
|||
|
},
|
|||
|
'销售/客服': {
|
|||
|
icon: '/static/common/icon/icon-9.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-9.png',
|
|||
|
},
|
|||
|
'资讯/法律/科研': {
|
|||
|
icon: '/static/common/icon/icon-10.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-10.png',
|
|||
|
},
|
|||
|
'会计/金融/银行/保险': {
|
|||
|
icon: '/static/common/icon/icon-11.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-11.png',
|
|||
|
},
|
|||
|
'生产/营运/采购/物流': {
|
|||
|
icon: '/static/common/icon/icon-12.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-12.png',
|
|||
|
},
|
|||
|
'学生': {
|
|||
|
icon: '/static/common/icon/icon-13.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-13.png',
|
|||
|
},
|
|||
|
'教师': {
|
|||
|
icon: '/static/common/icon/icon-14.png',
|
|||
|
minIcon: '/static/common/icon/min-icon-14.png',
|
|||
|
},
|
|||
|
},
|
|||
|
list: [],
|
|||
|
load: true,
|
|||
|
detailInfo: "",
|
|||
|
Showip: "",
|
|||
|
isExpanded: '0vh',
|
|||
|
touchStartY: 0,
|
|||
|
startScrollTop: 0,
|
|||
|
showPopup: false,
|
|||
|
timeer: null
|
|||
|
};
|
|||
|
},
|
|||
|
onLoad(e) {
|
|||
|
// if(!this.vuex_user.isCard){
|
|||
|
// uni.navigateTo({
|
|||
|
// url: '/pages/Face/index/index'
|
|||
|
// });
|
|||
|
// return
|
|||
|
// }
|
|||
|
// if (!this.vuex_user.isFill) {
|
|||
|
// uni.navigateTo({
|
|||
|
// url: "/pages/login/perfect/perfect",
|
|||
|
// });
|
|||
|
// return
|
|||
|
// } else {
|
|||
|
// this.$u.api.getUser()
|
|||
|
// }
|
|||
|
|
|||
|
console.info("🚀 ~ file:index method:onLoad line:374 -----", this.vuex_user)
|
|||
|
|
|||
|
this.center.imageUrl = this.vuex_user.head;
|
|||
|
this.center.workField = this.vuex_user?.workField?.workFieldName || "暂无";
|
|||
|
this.center.workFieldName = this.vuex_user?.workFieldName || "暂无";
|
|||
|
this.center.aiBlurb = this.vuex_user?.aiBlurb || "暂无";
|
|||
|
this.center.aiLabel = this.vuex_user?.aiLabel || "";
|
|||
|
this.center.college = this.vuex_user?.college || "";
|
|||
|
this.center.major = this.vuex_user?.major || "";
|
|||
|
this.center.startYear = this.vuex_user?.startYear || "";
|
|||
|
|
|||
|
// 创建地图上下文
|
|||
|
map = uni.createMapContext("map", this);
|
|||
|
uni.getSystemInfo({
|
|||
|
success: (res) => {
|
|||
|
this.height = res.windowHeight + "px";
|
|||
|
this.width = res.windowWidth + "px";
|
|||
|
},
|
|||
|
});
|
|||
|
// this.location();
|
|||
|
// qqmapsdk = new QQMapWX({
|
|||
|
// key: '2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS', //开发者密钥
|
|||
|
// })
|
|||
|
// console.log(this.vuex_user.isFill)
|
|||
|
},
|
|||
|
onShow() {
|
|||
|
/* uni.getSystemInfo({
|
|||
|
success: (res) => {
|
|||
|
this.viewHeight = res.windowHeight;
|
|||
|
},
|
|||
|
}); */
|
|||
|
|
|||
|
this.map.latitude = this.vuex_userLocation.latitude;
|
|||
|
this.map.longitude = this.vuex_userLocation.longitude;
|
|||
|
this.center.latitude = this.vuex_userLocation.latitude;
|
|||
|
this.center.longitude = this.vuex_userLocation.longitude;
|
|||
|
setTimeout(() => {
|
|||
|
if (!this.map.latitude || !this.map.longitude) {
|
|||
|
this.location(true);
|
|||
|
}
|
|||
|
this.test();
|
|||
|
}, 500);
|
|||
|
if (!this.vuex_user.isFill) {
|
|||
|
uni.navigateTo({
|
|||
|
url: "/pages/login/perfect/perfect",
|
|||
|
});
|
|||
|
return;
|
|||
|
} else {
|
|||
|
this.$u.api.getUser();
|
|||
|
}
|
|||
|
},
|
|||
|
methods: {
|
|||
|
// 回到当前位置
|
|||
|
backToLocation() {
|
|||
|
this.location(true);
|
|||
|
map.moveToLocation({
|
|||
|
latitude: this.vuex_userLocation.latitude || this.center.latitude,
|
|||
|
longitude: this.vuex_userLocation.longitude || this.center.longitude,
|
|||
|
});
|
|||
|
|
|||
|
this.latitude = this.vuex_userLocation.latitude || this.center.latitude;
|
|||
|
this.longitude = this.vuex_userLocation.longitude || this.center.longitude;
|
|||
|
},
|
|||
|
// 查看详情
|
|||
|
toDetil(id) {
|
|||
|
this.$u.route({
|
|||
|
url: "/pages/AlumniCircle/userDetail/userDetail?id=" + id,
|
|||
|
});
|
|||
|
},
|
|||
|
// 去聊天
|
|||
|
GoChat(id) {
|
|||
|
this.showInfo = false;
|
|||
|
uni.navigateTo({
|
|||
|
url:
|
|||
|
"../../message/dialogBox/dialogBox?id=" + id + "&chatType=0&type=0",
|
|||
|
});
|
|||
|
},
|
|||
|
toSearch() {
|
|||
|
if (this.vuex_user.isAttestationXY || true) {
|
|||
|
this.$u.route({
|
|||
|
url: "/pages/main/search/search",
|
|||
|
params: {
|
|||
|
type: 'index',
|
|||
|
},
|
|||
|
});
|
|||
|
} else {
|
|||
|
this.$refs.uToast.show({
|
|||
|
title: "认证后才能进行搜索哦",
|
|||
|
url: "/pages/my/ShoolList/ShoolList",
|
|||
|
});
|
|||
|
}
|
|||
|
},
|
|||
|
test() {
|
|||
|
map.getRegion({
|
|||
|
success: (res) => {
|
|||
|
this.Showip = {
|
|||
|
northeast: res.northeast,
|
|||
|
southwest: res.southwest,
|
|||
|
};
|
|||
|
this.getList();
|
|||
|
},
|
|||
|
});
|
|||
|
},
|
|||
|
getEpsByScale(zoomLevel) {
|
|||
|
// 缩放等级范围限制在 1 到 18
|
|||
|
if (zoomLevel < 1) zoomLevel = 1;
|
|||
|
if (zoomLevel > 18) zoomLevel = 18;
|
|||
|
|
|||
|
// 基础距离(单位:米),通常在缩放等级 0 时显示整个地球(约 40075 公里)
|
|||
|
const earthCircumference = 40075000; // 地球赤道周长(米)
|
|||
|
|
|||
|
// 根据缩放等级计算当前等级下的单个瓦片的地面宽度
|
|||
|
const tileSize = 256; // 地图瓦片大小(通常是 256x256 像素)
|
|||
|
const scale = 2 ** zoomLevel; // 缩放等级对应的缩放比例
|
|||
|
|
|||
|
// 计算每个像素代表的地面距离(米/像素)
|
|||
|
const metersPerPixel = earthCircumference / (tileSize * scale);
|
|||
|
|
|||
|
// 返回一个以 50 像素为参考的距离(可以根据需求调整这个值)
|
|||
|
const pixelRange = 50; // 聚合点之间的最小像素距离
|
|||
|
return metersPerPixel * pixelRange;
|
|||
|
},
|
|||
|
//根据东北 西南经纬度 以及后台返回标记点 格式化成marker点
|
|||
|
async getFortMatMarkerList(northeast, southwest, scale, backendMarkerList) {
|
|||
|
// 当前显示的坐标范围
|
|||
|
|
|||
|
// console.log(southwest.longitude, northeast.longitude, northeast.latitude, southwest.latitude)
|
|||
|
//屏幕中显示的经度的长度和纬度的长度
|
|||
|
let mapWidth = southwest.longitude - northeast.longitude;
|
|||
|
let mapHeight = northeast.latitude - southwest.latitude;
|
|||
|
//将屏幕中地图分割的横向 格子数和 纵向格子数
|
|||
|
// let widthSize = scale;
|
|||
|
// let heightSize = widthSize + parseInt(scale / 2);
|
|||
|
let widthSize = 30 - parseInt(scale / 2);
|
|||
|
let heightSize = 30 - parseInt(scale / 2);
|
|||
|
|
|||
|
//计算每个格子的经纬度的长度
|
|||
|
let unitWidth = mapWidth / widthSize;
|
|||
|
let unitHeight = mapHeight / heightSize;
|
|||
|
// console.log(southwest.longitude - northeast.longitude, unitHeight)
|
|||
|
let pointData = {};
|
|||
|
backendMarkerList.forEach((latLng) => {
|
|||
|
//如果点在显示范围内
|
|||
|
if (
|
|||
|
latLng.latitude < northeast.latitude &&
|
|||
|
latLng.latitude > southwest.latitude &&
|
|||
|
latLng.longitude < northeast.longitude &&
|
|||
|
latLng.longitude > southwest.longitude
|
|||
|
) {
|
|||
|
let relativeX = latLng.longitude - northeast.longitude;
|
|||
|
let relativeY = latLng.latitude - southwest.latitude;
|
|||
|
//计算出这个点,处于哪个格子
|
|||
|
let x = parseInt(Math.floor(relativeX / unitWidth));
|
|||
|
let y = parseInt(Math.floor(relativeY / unitHeight));
|
|||
|
if (x < 0 || y < 0) {
|
|||
|
console.log("点位不在格子内", "失败");
|
|||
|
}
|
|||
|
//生成单元格点位数据
|
|||
|
let pointKey = x + "," + y;
|
|||
|
if (pointData[pointKey] == undefined) {
|
|||
|
pointData[pointKey] = [];
|
|||
|
}
|
|||
|
if (pointData[pointKey].length <= 99) {
|
|||
|
pointData[pointKey].push(latLng);
|
|||
|
} else {
|
|||
|
return
|
|||
|
}
|
|||
|
} else {
|
|||
|
console.log("点位不在显示范围内", "失败");
|
|||
|
}
|
|||
|
});
|
|||
|
console.info("🚀 ~ file:index method:getFortMatMarkerList line:547 -----", pointData)
|
|||
|
|
|||
|
|
|||
|
// ===== 新增:使用 DBSCAN 进行全局点聚合 start =====
|
|||
|
const eps = this.getEpsByScale(scale); // 根据缩放级别调整 eps 值
|
|||
|
pointData = this.dbscan(pointData, parseInt(eps)); // 聚合参数可调整
|
|||
|
|
|||
|
|
|||
|
this.pointDataList = pointData;
|
|||
|
|
|||
|
|
|||
|
let resultMapArray = [];
|
|||
|
for (let y = 0; y < heightSize; y++) {
|
|||
|
for (let x = 0; x < widthSize; x++) {
|
|||
|
let pointKey = x + "," + y;
|
|||
|
if (
|
|||
|
pointData[pointKey] != undefined &&
|
|||
|
(pointData[pointKey][0].userId ||
|
|||
|
pointData[pointKey][0].userId === 0)
|
|||
|
) {
|
|||
|
let markerItem = {};
|
|||
|
|
|||
|
//聚合点与单点共存 , 长度等于一 不聚合点
|
|||
|
if (pointData[pointKey].length == 1) {
|
|||
|
var HeadImg = "/static/common/img/adminHeaderImg.png?number=1";
|
|||
|
if (pointData[pointKey][0].userId == 0) {
|
|||
|
if (this.vuex_user.sex == "男") {
|
|||
|
HeadImg = "/static/common/img/male.png?number=1";
|
|||
|
}
|
|||
|
if (this.vuex_user.sex == "女") {
|
|||
|
HeadImg = "/static/common/img/female.png?number=1";
|
|||
|
}
|
|||
|
}
|
|||
|
// 请求在线图片文件 判断是否存在
|
|||
|
// const imgExist = await this.doesImageExist(this.$u.http.config.imgUrl +
|
|||
|
// pointData[pointKey][0].imageUrl +
|
|||
|
// "?number=1");
|
|||
|
//
|
|||
|
// if (imgExist) {
|
|||
|
// HeadImg =
|
|||
|
// this.$u.http.config.imgUrl +
|
|||
|
// pointData[pointKey][0].imageUrl +
|
|||
|
// "?number=1";
|
|||
|
// }
|
|||
|
// 线上会出现奇怪的问题,所以先注释掉
|
|||
|
|
|||
|
if (pointData[pointKey][0].imageUrl != "") {
|
|||
|
HeadImg =
|
|||
|
this.$u.http.config.imgUrl +
|
|||
|
pointData[pointKey][0].imageUrl +
|
|||
|
"?number=1";
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
markerItem = {
|
|||
|
id: parseInt(
|
|||
|
(pointData[pointKey][0].latitude -
|
|||
|
-pointData[pointKey][0].longitude) *
|
|||
|
100000
|
|||
|
),
|
|||
|
latitude: pointData[pointKey][0].latitude,
|
|||
|
longitude: pointData[pointKey][0].longitude,
|
|||
|
iconPath: HeadImg,
|
|||
|
width: 50,
|
|||
|
height: 50,
|
|||
|
callout: {
|
|||
|
content: scale == 18 ? pointData[pointKey][0].aiLabel : '',
|
|||
|
display: 'ALWAYS',
|
|||
|
borderRadius: 100,
|
|||
|
bgColor: '#3CB5FB',
|
|||
|
color: '#fff',
|
|||
|
borderColor: '#3CB5FB',
|
|||
|
},
|
|||
|
label: {
|
|||
|
...this.callout,
|
|||
|
width: 50,
|
|||
|
height: 50,
|
|||
|
content: !this.careerList[pointData[pointKey][0].workFieldName] ? `` : `<img src="${this.careerList[pointData[pointKey][0].workFieldName].minIcon}">`
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
if (pointData[pointKey][0].userId === 0) {
|
|||
|
markerItem.id = '0'
|
|||
|
if (!pointData[pointKey][0].aiLabel) {
|
|||
|
markerItem.title = '我的位置'
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
// let iconPath = pointData[pointKey][0].ScanAndCharge == 1 ? '/img/scanMarkerIcon.png' : '/img/markerIcon.png';
|
|||
|
//长度大于一聚合点
|
|||
|
} else if (pointData[pointKey].length > 1) {
|
|||
|
// console.log('聚合点', pointData[pointKey]);
|
|||
|
// id会被转为number类型,字符类型不能触发点击时间,
|
|||
|
// 最后面加1是为了在结尾为0的情况时,0在转被为number不被裁剪掉,
|
|||
|
// 对比判断id时去掉加上的 1
|
|||
|
if (pointData[pointKey].length > 99) {
|
|||
|
pointData[pointKey] = pointData[pointKey].slice(0, 99)
|
|||
|
}
|
|||
|
|
|||
|
markerItem = {
|
|||
|
id: pointKey.split(",")[0] + "." + pointKey.split(",")[1] + "1",
|
|||
|
latitude: pointData[pointKey][0].latitude,
|
|||
|
longitude: pointData[pointKey][0].longitude,
|
|||
|
iconPath: await this.generateGroupAvatar(pointData[pointKey]), // 使用生成的群组头像
|
|||
|
width: 50,
|
|||
|
height: 50,
|
|||
|
list: pointData[pointKey],
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
resultMapArray.push(markerItem);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return resultMapArray;
|
|||
|
}
|
|||
|
,
|
|||
|
async doesImageExist(url) {
|
|||
|
try {
|
|||
|
const response = await fetch(url, {method: 'HEAD'});
|
|||
|
return response.ok;
|
|||
|
} catch (error) {
|
|||
|
console.error('图片不存在或发生错误:', error);
|
|||
|
return false;
|
|||
|
}
|
|||
|
},
|
|||
|
generateGroupAvatar(users) {
|
|||
|
|
|||
|
return new Promise((resolve, reject) => {
|
|||
|
try {
|
|||
|
const canvasSize = 100;
|
|||
|
const maxAvatars = 9;
|
|||
|
const filteredUsers = users.slice(0, maxAvatars);
|
|||
|
const total = filteredUsers.length;
|
|||
|
|
|||
|
if (total === 0) {
|
|||
|
resolve('/static/common/img/map_icon.png');
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 缓存 key
|
|||
|
const userIds = filteredUsers.map(u => u.userId).join(',');
|
|||
|
const cacheKey = `groupAvatar_${userIds}`;
|
|||
|
if (this[cacheKey]) {
|
|||
|
resolve(this[cacheKey]);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 创建 Canvas
|
|||
|
const canvas = document.createElement('canvas');
|
|||
|
canvas.width = canvasSize;
|
|||
|
canvas.height = canvasSize;
|
|||
|
const ctx = canvas.getContext('2d');
|
|||
|
ctx.fillStyle = '#ffffff';
|
|||
|
ctx.fillRect(0, 0, canvasSize, canvasSize);
|
|||
|
|
|||
|
let drawnCount = 0;
|
|||
|
const padding = 2;
|
|||
|
const verticalPadding = 3;
|
|||
|
|
|||
|
// 布局配置
|
|||
|
const layoutConfig = {
|
|||
|
1: {rows: 1, cols: 1, centeredRows: [0]},
|
|||
|
2: {rows: 1, cols: 2}, // 横向排列,但垂直居中
|
|||
|
3: {rows: 2, cols: [1, 2], centeredRows: [0]}, // 上1 下2,上居中
|
|||
|
4: {rows: 2, cols: 2}, // 2x2 四宫格
|
|||
|
5: {rows: 2, cols: [2, 3], centeredRows: [0]}, // 上2 下3,上居中
|
|||
|
6: {rows: 2, cols: 3}, // 上3 下3
|
|||
|
7: {rows: 3, cols: [1, 3, 3], centeredRows: [0]}, // 上1 中3 下3
|
|||
|
8: {rows: 3, cols: [2, 3, 3], centeredRows: [0]}, // 上2 中3 下3
|
|||
|
9: {rows: 3, cols: 3},
|
|||
|
};
|
|||
|
|
|||
|
const config = layoutConfig[total] || layoutConfig[9];
|
|||
|
const {rows, cols} = config;
|
|||
|
const colCounts = Array.isArray(cols) ? cols : Array(rows).fill(cols);
|
|||
|
const centeredRows = config.centeredRows || [];
|
|||
|
|
|||
|
// 计算最大列数,用于计算每个头像宽度
|
|||
|
const maxCols = Math.max(...colCounts);
|
|||
|
const avatarWidth = (canvasSize - padding * (maxCols - 1)) / maxCols;
|
|||
|
const rowHeight = (canvasSize - verticalPadding * (rows - 1)) / rows;
|
|||
|
|
|||
|
|
|||
|
// 绘制每个头像
|
|||
|
filteredUsers.forEach((user, index) => {
|
|||
|
const image = new Image();
|
|||
|
image.crossOrigin = 'anonymous';
|
|||
|
image.src = this.$u.http.config.imgUrl + user.imageUrl;
|
|||
|
|
|||
|
|
|||
|
// 确定当前头像属于哪一行
|
|||
|
let currentRow = 0;
|
|||
|
let count = 0;
|
|||
|
for (let i = 0; i < rows; i++) {
|
|||
|
const colCount = colCounts[i];
|
|||
|
if (index < count + colCount) {
|
|||
|
currentRow = i;
|
|||
|
break;
|
|||
|
}
|
|||
|
count += colCount;
|
|||
|
}
|
|||
|
|
|||
|
const colIndex = index - count;
|
|||
|
const currentColCount = colCounts[currentRow];
|
|||
|
|
|||
|
// 如果该行需要居中,则计算起始X坐标
|
|||
|
const startX = centeredRows.includes(currentRow)
|
|||
|
? (canvasSize - currentColCount * (avatarWidth + padding) + padding) / 2
|
|||
|
: 0;
|
|||
|
|
|||
|
const x = startX + colIndex * (avatarWidth + padding);
|
|||
|
const y = currentRow * (rowHeight + verticalPadding);
|
|||
|
|
|||
|
// 固定绘制为正方形,避免拉伸
|
|||
|
const drawSize = Math.min(avatarWidth, rowHeight);
|
|||
|
|
|||
|
// 居中绘制
|
|||
|
const offsetY = (rowHeight - drawSize) / 2;
|
|||
|
|
|||
|
image.onload = () => {
|
|||
|
ctx.save();
|
|||
|
ctx.beginPath();
|
|||
|
ctx.rect(x, y + offsetY, drawSize, drawSize);
|
|||
|
ctx.clip();
|
|||
|
|
|||
|
// 从图片中心裁剪出一个正方形
|
|||
|
const imgRatio = image.width / image.height;
|
|||
|
const cropSize = imgRatio > 1 ? image.height : image.width;
|
|||
|
const offsetX = (image.width - cropSize) / 2;
|
|||
|
const offsetYImg = (image.height - cropSize) / 2;
|
|||
|
|
|||
|
ctx.drawImage(
|
|||
|
image,
|
|||
|
offsetX, offsetYImg, cropSize, cropSize, // 源图裁剪区域
|
|||
|
x, y + offsetY, drawSize, drawSize // 目标绘制区域
|
|||
|
);
|
|||
|
|
|||
|
ctx.restore();
|
|||
|
|
|||
|
drawnCount++;
|
|||
|
if (drawnCount === filteredUsers.length) {
|
|||
|
// 如果超过最大数量,覆盖整个画布并居中显示 "+n"
|
|||
|
if (users.length > maxAvatars) {
|
|||
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
|
|||
|
ctx.beginPath();
|
|||
|
ctx.rect(0, 0, canvasSize, canvasSize);
|
|||
|
ctx.fill();
|
|||
|
|
|||
|
ctx.fillStyle = '#ffffff';
|
|||
|
ctx.font = 'bold 40px Arial';
|
|||
|
ctx.textAlign = 'center';
|
|||
|
ctx.textBaseline = 'middle';
|
|||
|
ctx.fillText(`+${users.length}`, canvasSize / 2, canvasSize / 2);
|
|||
|
}
|
|||
|
|
|||
|
// 缓存结果并返回
|
|||
|
const result = canvas.toDataURL('image/png');
|
|||
|
this[cacheKey] = result;
|
|||
|
resolve(result); // 异步完成
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
image.onerror = (err) => {
|
|||
|
image.src = "data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
|
|||
|
image.onload = () => {
|
|||
|
ctx.save();
|
|||
|
ctx.beginPath();
|
|||
|
ctx.rect(x, y + offsetY, drawSize, drawSize);
|
|||
|
ctx.clip();
|
|||
|
|
|||
|
// 从图片中心裁剪出一个正方形
|
|||
|
const imgRatio = image.width / image.height;
|
|||
|
const cropSize = imgRatio > 1 ? image.height : image.width;
|
|||
|
const offsetX = (image.width - cropSize) / 2;
|
|||
|
const offsetYImg = (image.height - cropSize) / 2;
|
|||
|
|
|||
|
ctx.drawImage(
|
|||
|
image,
|
|||
|
offsetX, offsetYImg, cropSize, cropSize, // 源图裁剪区域
|
|||
|
x, y + offsetY, drawSize, drawSize // 目标绘制区域
|
|||
|
);
|
|||
|
|
|||
|
ctx.restore();
|
|||
|
|
|||
|
drawnCount++;
|
|||
|
if (drawnCount === filteredUsers.length) {
|
|||
|
// 如果超过最大数量,覆盖整个画布并居中显示 "+n"
|
|||
|
if (users.length > maxAvatars) {
|
|||
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
|
|||
|
ctx.beginPath();
|
|||
|
ctx.rect(0, 0, canvasSize, canvasSize);
|
|||
|
ctx.fill();
|
|||
|
|
|||
|
ctx.fillStyle = '#ffffff';
|
|||
|
ctx.font = 'bold 40px Arial';
|
|||
|
ctx.textAlign = 'center';
|
|||
|
ctx.textBaseline = 'middle';
|
|||
|
ctx.fillText(`+${users.length}`, canvasSize / 2, canvasSize / 2);
|
|||
|
}
|
|||
|
|
|||
|
// 缓存结果并返回
|
|||
|
const result = canvas.toDataURL('image/png');
|
|||
|
this[cacheKey] = result;
|
|||
|
resolve(result); // 异步完成
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
});
|
|||
|
} catch (error) {
|
|||
|
console.error('生成聚合头像时发生异常:', error);
|
|||
|
resolve('/static/common/img/map_icon.png');
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
,
|
|||
|
/**
|
|||
|
* DBSCAN 聚类算法(输出格式与 pointData 一致)
|
|||
|
* @param points 原始点数组 { latitude, longitude }
|
|||
|
* @param eps 聚类距离阈值(单位:米)
|
|||
|
* @returns {{}} 统一格式的 pointData 结构,key 格式为 "x,y"
|
|||
|
*/
|
|||
|
dbscan(points, eps = 50) {
|
|||
|
|
|||
|
function getDistanceInMeters(lat1, lon1, lat2, lon2) {
|
|||
|
const R = 6371; // 地球半径(公里)
|
|||
|
const dLat = (lat2 - lat1) * Math.PI / 180;
|
|||
|
const dLon = (lon2 - lon1) * Math.PI / 180;
|
|||
|
const a =
|
|||
|
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
|||
|
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
|
|||
|
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|||
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|||
|
const distanceInKm = R * c;
|
|||
|
const distanceInMeters = distanceInKm * 1000; // 将公里转换为米
|
|||
|
console.info("🚀 ~ file:index method:getDistanceInMeters line:886 -----", distanceInMeters)
|
|||
|
|
|||
|
return parseInt(distanceInMeters) > 100000 ? 100000 : parseInt(distanceInMeters);
|
|||
|
}
|
|||
|
|
|||
|
let deletedPoints = [];
|
|||
|
for (let key in points) {
|
|||
|
if (deletedPoints.includes(key)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
let X = key.split(',')[0]
|
|||
|
let Y = key.split(',')[1]
|
|||
|
for (let keyTwo in points) {
|
|||
|
let innerX = keyTwo.split(',')[0]
|
|||
|
let innerY = keyTwo.split(',')[1]
|
|||
|
if (key === keyTwo) {
|
|||
|
continue
|
|||
|
}
|
|||
|
if (Math.abs(X - innerX) <= 1 && Math.abs(Y - innerY) <= 1) {
|
|||
|
if (getDistanceInMeters(points[key][0].latitude, points[key][0].longitude, points[keyTwo][0].latitude, points[keyTwo][0].longitude) < eps) {
|
|||
|
points[key] = points[key].concat(points[keyTwo])
|
|||
|
deletedPoints.push(keyTwo)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
for (let key in points) {
|
|||
|
if (deletedPoints.includes(key)) {
|
|||
|
delete points[key]
|
|||
|
}
|
|||
|
}
|
|||
|
return points;
|
|||
|
// ===== 构造统一格式 end =====
|
|||
|
}
|
|||
|
|
|||
|
,
|
|||
|
/**
|
|||
|
* 将聚类结果转为类似 pointData 的结构("x,y": [])
|
|||
|
* @param clusters 聚类结果二维数组
|
|||
|
* @param noise 噪声点
|
|||
|
* @returns [[]] 合并后的伪格子结构
|
|||
|
*/
|
|||
|
_generateFakeGrids(clusters, noise) {
|
|||
|
const result = [...clusters]; // 每个 cluster 单独作为一个格子
|
|||
|
|
|||
|
// 如果需要可选地将噪声点也作为一个格子加入
|
|||
|
if (noise.length > 0) {
|
|||
|
result.push(noise); // 可选
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
,
|
|||
|
updated() {
|
|||
|
// console.log("渲染完成");
|
|||
|
}
|
|||
|
,
|
|||
|
// 当视野发生改变
|
|||
|
regionchange(e) {
|
|||
|
// console.log("当视野发生改变");
|
|||
|
// 视野移动结束再获取数据
|
|||
|
if (e.type == "begin") return;
|
|||
|
// 关闭显示的窗口
|
|||
|
this.showInfo = false
|
|||
|
|
|||
|
this.test()
|
|||
|
|
|||
|
// let loadDelay = 200;
|
|||
|
// if (this.load) {
|
|||
|
// // console.log("等待加载");
|
|||
|
// } else {
|
|||
|
// this.load = true;
|
|||
|
// setTimeout(() => {
|
|||
|
// // this.getList();
|
|||
|
// this.test();
|
|||
|
// }, loadDelay);
|
|||
|
// }
|
|||
|
}
|
|||
|
,
|
|||
|
isWechat() {
|
|||
|
var ua = window.navigator.userAgent.toLowerCase();
|
|||
|
if (ua.match(/micromessenger/i) == "micromessenger") {
|
|||
|
// console.log(‘是微信客户端’)
|
|||
|
return true;
|
|||
|
} else {
|
|||
|
// console.log(‘不是微信客户端’)
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
,
|
|||
|
//在需要定位页面调用
|
|||
|
getlocation: function (callback) {
|
|||
|
if (!this.isWechat()) {
|
|||
|
//console.log('不是微信客户端')
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
,
|
|||
|
//打开位置
|
|||
|
openlocation: function (data) {
|
|||
|
if (!this.isWechat()) {
|
|||
|
//console.log('不是微信客户端')
|
|||
|
return;
|
|||
|
}
|
|||
|
jweixin.ready(function () {
|
|||
|
jweixin.openLocation({
|
|||
|
latitude: data.latitude,
|
|||
|
longitude: data.longitude,
|
|||
|
name: data.name,
|
|||
|
address: data.address,
|
|||
|
scale: 14,
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
,
|
|||
|
//定位当前
|
|||
|
location(state) {
|
|||
|
var that = this;
|
|||
|
uni.showLoading({
|
|||
|
title: '正在加载...',
|
|||
|
mask: true
|
|||
|
})
|
|||
|
if (state && this.isWechat()) {
|
|||
|
const isiOS = !!navigator.userAgent.match(
|
|||
|
/\(i[^;]+;( U;)? CPU.+Mac OS X/
|
|||
|
); //ios终端
|
|||
|
// 进行签名的时候 Android 不用使用之前的链接, ios 需要
|
|||
|
const signLink = isiOS
|
|||
|
? window.entryUrl
|
|||
|
: window.location.href.split("#")[0];
|
|||
|
//获取当前url然后传递给后台获取授权和签名信息,后台需要解码才能使用
|
|||
|
// const url =encodeURIComponent(signLink);
|
|||
|
const url = signLink;
|
|||
|
const data = {
|
|||
|
url: url,
|
|||
|
};
|
|||
|
|
|||
|
this.$u.api.GetInfoMation(data).then((res) => {
|
|||
|
jweixin.config({
|
|||
|
debug: false,
|
|||
|
appId: res.appId,
|
|||
|
timestamp: res.timestamp,
|
|||
|
nonceStr: res.noncestr,
|
|||
|
signature: res.signature,
|
|||
|
jsApiList: [
|
|||
|
//这里是需要用到的接口名称
|
|||
|
"getLocation", //获取位置
|
|||
|
"openLocation", //打开位置
|
|||
|
],
|
|||
|
});
|
|||
|
|
|||
|
// jweixin.config 执行失败时调用
|
|||
|
jweixin.error((err) => {
|
|||
|
uni.hideLoading();
|
|||
|
that.location(false);
|
|||
|
console.log("授权失败,您可能无法使用部分功能", err);
|
|||
|
});
|
|||
|
jweixin.ready(function () {
|
|||
|
jweixin.getLocation({
|
|||
|
type: "gcj02", // 默认为wgs84的gps坐标,如果要返 回直接给openLocation用的火星坐标,可传入'gcj02'
|
|||
|
success: (res) => {
|
|||
|
uni.hideLoading();
|
|||
|
var resdata = res;
|
|||
|
// console.log(res,'success');
|
|||
|
map.moveToLocation({
|
|||
|
latitude: resdata.latitude,
|
|||
|
longitude: resdata.longitude,
|
|||
|
});
|
|||
|
// alert(JSON.stringify(res))
|
|||
|
that.center.latitude = resdata.latitude; //纬度
|
|||
|
that.center.longitude = resdata.longitude; //经度
|
|||
|
|
|||
|
// 更新坐标
|
|||
|
var data = {
|
|||
|
userId: that.vuex_user.id,
|
|||
|
longitude: resdata.longitude + "",
|
|||
|
latitude: resdata.latitude + "",
|
|||
|
};
|
|||
|
that.$u.api.upPosition(data).then(() => {
|
|||
|
that.getList(resdata.latitude, resdata.longitude);
|
|||
|
that.test();
|
|||
|
});
|
|||
|
},
|
|||
|
fail: function (res) {
|
|||
|
uni.hideLoading();
|
|||
|
// console.log(res, "err");
|
|||
|
},
|
|||
|
complete: function (res) {
|
|||
|
uni.hideLoading();
|
|||
|
// console.log(res, "is");
|
|||
|
},
|
|||
|
});
|
|||
|
});
|
|||
|
});
|
|||
|
} else {
|
|||
|
uni.getLocation({
|
|||
|
// type: "wgs84 ",
|
|||
|
type: "gcj02 ",
|
|||
|
isHighAccuracy: true,
|
|||
|
highAccuracyExpireTime: 3000,
|
|||
|
success: (res) => {
|
|||
|
|
|||
|
uni.hideLoading();
|
|||
|
// console.info("🚀 ~ file:index method:success line:497 -----", res);
|
|||
|
|
|||
|
// console.log(res.latitude + "," + res.longitude, "gcj02");
|
|||
|
map.moveToLocation({
|
|||
|
latitude: res.latitude,
|
|||
|
longitude: res.longitude,
|
|||
|
});
|
|||
|
this.center.latitude = res.latitude; //纬度
|
|||
|
this.center.longitude = res.longitude; //经度
|
|||
|
|
|||
|
// 更新坐标
|
|||
|
var data = {
|
|||
|
userId: this.vuex_user.id,
|
|||
|
longitude: res.longitude + "",
|
|||
|
latitude: res.latitude + "",
|
|||
|
};
|
|||
|
this.$u.api.upPosition(data).then(() => {
|
|||
|
this.getList(res.latitude, res.longitude);
|
|||
|
this.test();
|
|||
|
});
|
|||
|
},
|
|||
|
fail: (err) => {
|
|||
|
uni.hideLoading();
|
|||
|
console.log("地理位置获取失败", err);
|
|||
|
},
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
,
|
|||
|
|
|||
|
testlist() {
|
|||
|
// this.getList();
|
|||
|
this.test();
|
|||
|
}
|
|||
|
,
|
|||
|
// 获取用户列表
|
|||
|
getList(la = 0, lo = 0) {
|
|||
|
var arr = [];
|
|||
|
map.getCenterLocation({
|
|||
|
success: (res) => {
|
|||
|
let latitude = res.latitude;
|
|||
|
let longitude = res.longitude;
|
|||
|
if (la !== 0) {
|
|||
|
latitude = la;
|
|||
|
longitude = lo;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// console.info("🚀 ~ file:index method:success line:1038 -----", latitude,longitude)
|
|||
|
this.latitude = latitude;
|
|||
|
this.longitude = longitude;
|
|||
|
let data = {
|
|||
|
userId: this.vuex_user.id,
|
|||
|
lat: this.center.latitude,
|
|||
|
lon: this.center.longitude,
|
|||
|
nort_lat: this.Showip?.northeast?.latitude || 0,
|
|||
|
nort_lon: this.Showip?.northeast?.longitude || 0,
|
|||
|
sout_lat: this.Showip?.southwest?.latitude || 0,
|
|||
|
sout_lon: this.Showip?.southwest?.longitude || 0,
|
|||
|
};
|
|||
|
if (this.timeer) {
|
|||
|
clearTimeout(this.timeer)
|
|||
|
}
|
|||
|
this.timeer = setTimeout(() => {
|
|||
|
this.$u.api.HomeMap(data).then((res) => {
|
|||
|
if (res) {
|
|||
|
res.unshift(this.center);
|
|||
|
// res = res.reverse();
|
|||
|
this.list = res;
|
|||
|
// this.test();
|
|||
|
} else {
|
|||
|
/* uni.showToast({
|
|||
|
title: res.data.msg,
|
|||
|
icon: "none",
|
|||
|
}); */
|
|||
|
}
|
|||
|
map.getScale({
|
|||
|
success: async (ress) => {
|
|||
|
this.covers = await this.getFortMatMarkerList(
|
|||
|
this.Showip.northeast,
|
|||
|
this.Showip.southwest,
|
|||
|
ress.scale,
|
|||
|
this.list
|
|||
|
);
|
|||
|
document.querySelectorAll(
|
|||
|
"#map .csssprite:nth-child(1)"
|
|||
|
)[0].style.border = "none";
|
|||
|
},
|
|||
|
});
|
|||
|
}).catch(() => {
|
|||
|
this.list = [this.center];
|
|||
|
map.getScale({
|
|||
|
success: async (ress) => {
|
|||
|
this.covers = await this.getFortMatMarkerList(
|
|||
|
this.Showip.northeast,
|
|||
|
this.Showip.southwest,
|
|||
|
ress.scale,
|
|||
|
this.list
|
|||
|
);
|
|||
|
document.querySelectorAll(
|
|||
|
"#map .csssprite:nth-child(1)"
|
|||
|
)[0].style.border = "none";
|
|||
|
},
|
|||
|
});
|
|||
|
});
|
|||
|
}, 500)
|
|||
|
},
|
|||
|
});
|
|||
|
}
|
|||
|
,
|
|||
|
tap() {
|
|||
|
this.showInfo = false;
|
|||
|
}
|
|||
|
,
|
|||
|
// 点击获取当前用户信息 注意:<每个 marker 点都必须要有id 不然点击maxker的事件不会触发>
|
|||
|
getUserDetail(i) {
|
|||
|
// console.info(
|
|||
|
// "🚀 ~ file:index method:getUserDetail line:574 -----",
|
|||
|
// i.detail.markerId
|
|||
|
// );
|
|||
|
|
|||
|
//点击中心点时不显示
|
|||
|
if (i.detail.markerId == 0) return;
|
|||
|
// 判断是否是聚合点
|
|||
|
this.detailInfoList = [];
|
|||
|
if (String(i.detail.markerId).split(".").length > 1) {
|
|||
|
var pointKey = String(i.detail.markerId).replace(".", ",");
|
|||
|
pointKey = pointKey.slice(0, pointKey.length - 1);
|
|||
|
let arr = this.pointDataList[pointKey];
|
|||
|
let isprovince = "";
|
|||
|
let iscity = "";
|
|||
|
// 地址解析 免费 每日10000请求量
|
|||
|
uni.showLoading({
|
|||
|
title: "加载中",
|
|||
|
});
|
|||
|
this.$jsonp(
|
|||
|
"https://apis.map.qq.com/ws/geocoder/v1/?key=2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS&location=" +
|
|||
|
arr[0].latitude +
|
|||
|
"," +
|
|||
|
arr[0].longitude +
|
|||
|
"&output=jsonp&get_poi=1"
|
|||
|
).then((res) => {
|
|||
|
if (res.status == 0) {
|
|||
|
isprovince = res.result.address_component.province;
|
|||
|
iscity = res.result.address_component.city;
|
|||
|
for (let i in arr) {
|
|||
|
arr[i].province = isprovince ? isprovince : "未";
|
|||
|
arr[i].city = iscity ? iscity : "知";
|
|||
|
}
|
|||
|
this.detailInfoList = arr;
|
|||
|
this.isExpanded = '0vh';
|
|||
|
this.showPopup = true
|
|||
|
setTimeout(() => {
|
|||
|
this.isExpanded = '90vh';
|
|||
|
}, 10);
|
|||
|
// this.showList();
|
|||
|
uni.hideLoading();
|
|||
|
}
|
|||
|
});
|
|||
|
} else {
|
|||
|
|
|||
|
// 根据id筛选获取用户信息
|
|||
|
let a = this.list.filter((item) => {
|
|||
|
|
|||
|
return (
|
|||
|
parseInt((item.latitude - -item.longitude) * 100000) ==
|
|||
|
i.detail.markerId
|
|||
|
);
|
|||
|
})[0];
|
|||
|
|
|||
|
if (a.userId == this.detailInfo.userId) {
|
|||
|
setTimeout(() => {
|
|||
|
this.showInfo = true;
|
|||
|
this.showPopup = false
|
|||
|
}, 100);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 地址解析
|
|||
|
this.$jsonp(
|
|||
|
"https://apis.map.qq.com/ws/geocoder/v1/?key=2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS&location=" +
|
|||
|
a.latitude +
|
|||
|
"," +
|
|||
|
a.longitude +
|
|||
|
"&output=jsonp&get_poi=1"
|
|||
|
).then((res) => {
|
|||
|
// console.log("解析地址成功", res);
|
|||
|
// console.log("当前地址:", res.result.address);
|
|||
|
if (res.status == 0) {
|
|||
|
a.province = res.result.address_component.province;
|
|||
|
a.city = res.result.address_component.city;
|
|||
|
}
|
|||
|
this.detailInfo = a;
|
|||
|
setTimeout(() => {
|
|||
|
this.showInfo = true;
|
|||
|
this.showPopup = false
|
|||
|
}, 100);
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
,
|
|||
|
|
|||
|
togglePopup() {
|
|||
|
this.isExpanded = '90vh';
|
|||
|
}
|
|||
|
,
|
|||
|
touchStart(e) {
|
|||
|
// 记录起始触摸点
|
|||
|
this.touchStartY = e.touches[0].clientY;
|
|||
|
// 记录起始滚动位置
|
|||
|
this.startScrollTop = e.currentTarget.scrollTop;
|
|||
|
}
|
|||
|
,
|
|||
|
touchMove(e) {
|
|||
|
|
|||
|
const currentY = e.touches[0].clientY;
|
|||
|
const diff = this.touchStartY - currentY;
|
|||
|
const scrollTop = e.currentTarget.scrollTop;
|
|||
|
|
|||
|
// 判断是否在内容顶部或底部
|
|||
|
const isAtTop = scrollTop <= 0;
|
|||
|
const isAtBottom = scrollTop + e.currentTarget.clientHeight >= e.currentTarget.scrollHeight;
|
|||
|
|
|||
|
// 在顶部向下滑动或在底部向上滑动时,阻止默认行为
|
|||
|
if ((isAtTop && diff < 0) || (isAtBottom && diff > 0)) {
|
|||
|
e.preventDefault();
|
|||
|
}
|
|||
|
|
|||
|
// 向上滑动超过50px时展开
|
|||
|
if (diff > 50) {
|
|||
|
this.isExpanded = '90vh';
|
|||
|
}
|
|||
|
// 向下滑动超过50px时收起
|
|||
|
else if (diff < -50) {
|
|||
|
if (this.isExpanded == '40vh') {
|
|||
|
console.log("关闭");
|
|||
|
this.isExpanded = '0vh';
|
|||
|
setTimeout(() => {
|
|||
|
this.showPopup = false
|
|||
|
}, 100);
|
|||
|
} else {
|
|||
|
console.log("收起");
|
|||
|
this.isExpanded = '40vh';
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
,
|
|||
|
touchMoveFn(e) {
|
|||
|
if (this.timeer) {
|
|||
|
clearTimeout(this.timeer)
|
|||
|
}
|
|||
|
this.timeer = setTimeout(() => {
|
|||
|
this.touchMove(e)
|
|||
|
}, 100)
|
|||
|
}
|
|||
|
,
|
|||
|
touchEnd(e) {
|
|||
|
// 可以在这里添加滑动结束后的处理逻辑
|
|||
|
}
|
|||
|
,
|
|||
|
},
|
|||
|
};
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped lang="scss">
|
|||
|
.AIdescribe {
|
|||
|
display: block;
|
|||
|
font-size: 26rpx;
|
|||
|
color: rgba(0, 0, 0, 0.4);
|
|||
|
line-height: 30rpx;
|
|||
|
text-align: left;
|
|||
|
margin-top: 20rpx;
|
|||
|
max-width: 67vw;
|
|||
|
white-space: break-spaces;
|
|||
|
}
|
|||
|
|
|||
|
.tags {
|
|||
|
gap: 10rpx;
|
|||
|
margin-top: 20rpx;
|
|||
|
}
|
|||
|
|
|||
|
.h100 {
|
|||
|
height: 100%
|
|||
|
}
|
|||
|
|
|||
|
.search-box {
|
|||
|
width: 72rpx;
|
|||
|
height: 72rpx;
|
|||
|
border-radius: 50%;
|
|||
|
background: #fff;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
|
|||
|
position: absolute;
|
|||
|
top: 50rpx;
|
|||
|
left: 50rpx;
|
|||
|
z-index: 1;
|
|||
|
box-shadow: 0rpx 10rpx 10rpx -6rpx rgba(0, 0, 0, 0.1),
|
|||
|
0rpx 16rpx 20rpx 2rpx rgba(0, 0, 0, 0.06),
|
|||
|
0rpx 6rpx 28rpx 4rpx rgba(0, 0, 0, 0.05);
|
|||
|
}
|
|||
|
|
|||
|
::v-deep .uni-scroll-view-content {
|
|||
|
background: #f6f8f9 !important;
|
|||
|
}
|
|||
|
|
|||
|
::v-deep #map .csssprite {
|
|||
|
border-radius: 50%;
|
|||
|
border: 2px solid #358ddf !important;
|
|||
|
filter: drop-shadow(0px 0px 2px #358ddf);
|
|||
|
transform: scale(0.8);
|
|||
|
}
|
|||
|
|
|||
|
::v-deep #map > div > div > div > div > div:nth-last-child(4) > div > div {
|
|||
|
overflow: initial !important;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// ::v-deep #map>div>div>div>div>div:nth-last-child(4)>div>div:nth-child(1)>.csssprite[src=''] {
|
|||
|
// border: none !important;
|
|||
|
// }
|
|||
|
.name-work {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
padding-left: 20rpx;
|
|||
|
}
|
|||
|
|
|||
|
.info {
|
|||
|
position: absolute;
|
|||
|
right: 0;
|
|||
|
left: 0;
|
|||
|
transform: translateY(-125%);
|
|||
|
|
|||
|
.section_2 {
|
|||
|
padding: 0.11rem 0.18rem 0.15rem 0.21rem;
|
|||
|
background-color: rgb(255, 255, 255);
|
|||
|
box-shadow: 0px 0px 0.1rem rgba(0, 0, 0, 0.1);
|
|||
|
border-radius: 0.1rem;
|
|||
|
|
|||
|
.text_3 {
|
|||
|
color: #3CB5FB;
|
|||
|
font-size: 26rpx;
|
|||
|
white-space: nowrap;
|
|||
|
overflow: hidden;
|
|||
|
text-overflow: ellipsis;
|
|||
|
margin-left: 10rpx;
|
|||
|
vertical-align: middle;
|
|||
|
|
|||
|
img {
|
|||
|
vertical-align: middle;
|
|||
|
Width: 48rpx;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.group_6 {
|
|||
|
white-space: nowrap;
|
|||
|
border-top: 1px solid #F4F6F8;
|
|||
|
padding-top: 20rpx;
|
|||
|
margin-top: 20rpx;
|
|||
|
|
|||
|
.text_4 {
|
|||
|
margin-right: 0.1rem;
|
|||
|
color: rgb(63, 63, 63);
|
|||
|
font-size: 0.14rem;
|
|||
|
line-height: 0.16rem;
|
|||
|
white-space: nowrap;
|
|||
|
}
|
|||
|
|
|||
|
.text_5 {
|
|||
|
font-size: 28rpx;
|
|||
|
color: rgba(0, 0, 0, 0.6);
|
|||
|
line-height: 0.16rem;
|
|||
|
letter-spacing: 0.014rem;
|
|||
|
white-space: nowrap;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.group_5 {
|
|||
|
color: rgb(56, 58, 63);
|
|||
|
font-size: 0.18rem;
|
|||
|
line-height: 0.17rem;
|
|||
|
white-space: nowrap;
|
|||
|
|
|||
|
.image_5 {
|
|||
|
width: 0.44rem;
|
|||
|
height: 0.44rem;
|
|||
|
border-radius: 50%;
|
|||
|
}
|
|||
|
|
|||
|
.text_1 {
|
|||
|
font-size: 30rpx;
|
|||
|
// margin-left: 0.13rem;
|
|||
|
//margin-top: 22rpx;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.section_3 {
|
|||
|
padding: 20rpx 20rpx;
|
|||
|
color: rgb(255, 255, 255);
|
|||
|
font-size: 24rpx;
|
|||
|
white-space: nowrap;
|
|||
|
background-color: #3cb5fb;
|
|||
|
border-radius: 0.15rem;
|
|||
|
height: 56rpx;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
position: absolute;
|
|||
|
right: 0;
|
|||
|
top: 50%;
|
|||
|
transform: translateY(-50%);
|
|||
|
|
|||
|
.image_6 {
|
|||
|
width: 32rpx;
|
|||
|
height: 32rpx;
|
|||
|
}
|
|||
|
|
|||
|
.text_2 {
|
|||
|
margin-left: 0.055rem;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// .text {
|
|||
|
// text-transform: uppercase;
|
|||
|
// }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.bottom {
|
|||
|
position: fixed;
|
|||
|
z-index: 10;
|
|||
|
bottom: 0;
|
|||
|
right: 2%;
|
|||
|
left: 2%;
|
|||
|
padding-bottom: 0.48rem;
|
|||
|
|
|||
|
.btn {
|
|||
|
display: flex;
|
|||
|
justify-content: center;
|
|||
|
margin-top: 0.22rem;
|
|||
|
}
|
|||
|
|
|||
|
.section_4 {
|
|||
|
margin-right: 0.025rem;
|
|||
|
margin-top: 0.17rem;
|
|||
|
padding: 0.2rem 0.2rem 0.3rem;
|
|||
|
color: rgb(193, 196, 204);
|
|||
|
font-size: 0.14rem;
|
|||
|
line-height: 0.14rem;
|
|||
|
white-space: nowrap;
|
|||
|
background-color: rgb(255, 255, 255);
|
|||
|
box-shadow: 0px 0px 0.03rem rgba(0, 0, 0, 0.1);
|
|||
|
border-radius: 0.1rem 0.1rem 0 0;
|
|||
|
|
|||
|
.search {
|
|||
|
margin-left: 0.14rem;
|
|||
|
margin-right: 0.1rem;
|
|||
|
padding: 0.14rem 0 0.13rem;
|
|||
|
background-color: rgb(246, 247, 250);
|
|||
|
border-radius: 0.05rem;
|
|||
|
|
|||
|
// .text {
|
|||
|
// text-transform: uppercase;
|
|||
|
// }
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.popup-box {
|
|||
|
position: fixed;
|
|||
|
left: 0;
|
|||
|
right: 0;
|
|||
|
bottom: 0;
|
|||
|
min-height: 240rpx;
|
|||
|
box-shadow: 0rpx -14rpx 16rpx 0rpx rgba(0, 0, 0, 0.06);
|
|||
|
border-top-left-radius: 40rpx;
|
|||
|
border-top-right-radius: 40rpx;
|
|||
|
transition: all 0.3s ease;
|
|||
|
z-index: 100;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
.popup-top {
|
|||
|
// position: fixed;
|
|||
|
// top: 0;
|
|||
|
width: 100%;
|
|||
|
padding-top: 20rpx;
|
|||
|
background: #fff;
|
|||
|
border-top-left-radius: 40rpx;
|
|||
|
border-top-right-radius: 40rpx;
|
|||
|
cursor: pointer; // 添加手型光标
|
|||
|
}
|
|||
|
|
|||
|
.pop-top {
|
|||
|
width: 88rpx;
|
|||
|
height: 10rpx;
|
|||
|
background: #9ea1b9;
|
|||
|
border-radius: 200rpx;
|
|||
|
margin: 20rpx auto 0;
|
|||
|
}
|
|||
|
|
|||
|
.pop-title {
|
|||
|
padding: 20rpx 32rpx 40rpx;
|
|||
|
font-weight: 600;
|
|||
|
font-size: 32rpx;
|
|||
|
color: #191919;
|
|||
|
background: #fff;
|
|||
|
}
|
|||
|
|
|||
|
.content {
|
|||
|
height: calc(100% - 174rpx) !important;
|
|||
|
overflow-y: auto;
|
|||
|
background: #f6f8f9;
|
|||
|
padding: 30rpx 30rpx 50rpx;
|
|||
|
// -webkit-overflow-scrolling: touch;
|
|||
|
}
|
|||
|
|
|||
|
.back-to-location {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
position: absolute;
|
|||
|
bottom: 180rpx;
|
|||
|
right: 50rpx;
|
|||
|
z-index: 1;
|
|||
|
}
|
|||
|
|
|||
|
::v-deep #map > div:nth-child(1) > div > div:nth-child(1) > div > div:nth-child(2) {
|
|||
|
z-index: 999999 !important;
|
|||
|
}
|
|||
|
|
|||
|
::v-deep #map a[title="到腾讯地图查看此区域"] {
|
|||
|
display: none !important;
|
|||
|
}
|
|||
|
|
|||
|
.position-relative {
|
|||
|
position: relative;
|
|||
|
}
|
|||
|
</style>
|