YingXingAI/pages/main/index/index.vue

1634 lines
57 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>
<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" 缩放max18 min5-->
<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/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYG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";
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>