You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

610 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="map-container">
<map
id="schoolmateMap"
min-scale="6"
max-scale="16"
:longitude="lng"
:latitude="lat"
:scale="scale"
:markers="mapMarkers"
show-location
@regionchange="onRegionChange"
@markertap="showCompanyDetail"
@tap="onMapTap"
>
</map>
<!-- 公司详情信息 -->
<view class="company-info" v-if="showCompanyInfo && selectedCompany">
<view class="company-info-content">
<view class="company-info-title">
<view class="company-name">{{ selectedCompany.company_name || selectedCompany.name || '校友公司' }}</view>
<u-icon name="close" size="40" color="#919191" @click="closeCompanyDetail"></u-icon>
</view>
<view class="company-info-details">
<!-- 校友信息 -->
<view class="company-users" v-if="selectedCompany.users && selectedCompany.users.length > 0">
<!-- <text class="label">校友:</text> -->
<view class="users-list">
<view class="user-item" v-for="(user, index) in selectedCompany.users" :key="index">
<!-- {{ user.course_signs[0].course.type_detail ? user.course_signs[0].course.type_detail.name + '|' : '' }} -->
<view class="user-course" v-if="user.course_signs && user.course_signs.length > 0 && user.course_signs[0].course">
<text class="course-text">{{ user.course_signs[0].course.year ? user.course_signs[0].course.year + '年' : '' }}{{ user.course_signs[0].course.name || '' }}</text>
</view>
<!-- 校友姓名和职务 -->
<view class="user-info">
<text class="user-name">{{ user.name }}</text>
<text class="user-position" v-if="user.company_position">{{ user.company_position }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 定位提示 -->
<view class="location-tip" v-if="showLocationTip" @click="retryLocationAuth">
使用完整功能,需要获取您的定位,点击授权
</view>
<!-- 加载提示 -->
<view class="loading-tip" v-if="isLoading">
正在获取位置信息...
</view>
<!-- 数据加载提示 -->
<view class="data-loading" v-if="isDataLoading">
<!-- <u-loading-icon mode="spinner" size="28"></u-loading-icon> -->
<text>正在加载校友数据...</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
lng: 120.619585, // 默认经度(苏州)
lat: 31.299038, // 默认纬度(苏州)
scale: 11, // 地图缩放级别
showLocationTip: false, // 是否显示定位提示
isLoading: true, // 是否正在加载位置
isDataLoading: false, // 是否正在加载数据
mapContext: null, // 地图上下文
mapMarkers: [], // 地图标记点用于map组件的markers属性
companies: [], // 校友公司数据
currentPage: 1, // 当前页码
pageSize: 50, // 每页数量
hasMore: true, // 是否还有更多数据
userLocation: null, // 用户位置信息
showCompanyInfo: false, // 是否显示公司详情
selectedCompany: null // 选中的公司详情
}
},
onReady() {
this.initLocationAuth()
this.mapContext = uni.createMapContext('schoolmateMap', this)
},
onLoad() {
// 页面加载时的初始化
},
methods: {
// 初始化定位权限
initLocationAuth() {
uni.getSetting({
success: (res) => {
const setting = res.authSetting || {}
const loc = setting['scope.userLocation']
if (loc === true) {
// 已授权,获取位置
this.showLocationTip = false
this.getUserLocation()
} else if (loc === false) {
// 已拒绝授权
this.showLocationTip = true
this.isLoading = false
// 使用默认位置加载数据
this.loadCompanyData()
} else {
// 首次使用,尝试授权
uni.authorize({
scope: 'scope.userLocation',
success: () => {
this.showLocationTip = false
this.getUserLocation()
},
fail: () => {
this.showLocationTip = true
this.isLoading = false
// 使用默认位置加载数据
this.loadCompanyData()
}
})
}
},
fail: () => {
this.showLocationTip = true
this.isLoading = false
// 使用默认位置加载数据
this.loadCompanyData()
}
})
},
// 获取用户位置
getUserLocation() {
uni.getLocation({
type: 'gcj02', // 使用国测局坐标系
success: (res) => {
this.showLocationTip = false
this.isLoading = false
// 设置地图中心点为用户当前位置
this.lng = res.longitude
this.lat = res.latitude
// 保存位置信息
this.userLocation = {
lng: this.lng,
lat: this.lat
}
// 保存位置信息到本地存储
uni.setStorageSync('vuex_latlng', {
lng: this.lng,
lat: this.lat
})
console.log('获取位置成功:', {
longitude: this.lng,
latitude: this.lat
})
// 加载校友数据
this.loadCompanyData()
},
fail: (err) => {
console.log("获取位置失败:", err)
this.showLocationTip = true
this.isLoading = false
// 使用默认位置加载数据
this.loadCompanyData()
}
})
},
// 重试定位授权
retryLocationAuth() {
uni.getSetting({
success: (res) => {
const setting = res.authSetting || {}
const loc = setting['scope.userLocation']
if (loc === true) {
// 已授权,重新获取位置
this.showLocationTip = false
this.getUserLocation()
} else if (loc === false) {
// 已拒绝,打开设置页面
uni.openSetting({
success: (rs) => {
if (rs.authSetting && rs.authSetting['scope.userLocation']) {
this.showLocationTip = false
this.getUserLocation()
}
}
})
} else {
// 重新授权
uni.authorize({
scope: 'scope.userLocation',
success: () => {
this.showLocationTip = false
this.getUserLocation()
},
fail: () => {
uni.openSetting({
success: (rs) => {
if (rs.authSetting && rs.authSetting['scope.userLocation']) {
this.showLocationTip = false
this.getUserLocation()
}
}
})
}
})
}
}
})
},
// 加载校友公司数据
async loadCompanyData() {
if (this.isDataLoading || !this.hasMore) return
this.isDataLoading = true
try {
// 使用用户位置或默认位置
const params = {
company_longitude: this.userLocation ? this.userLocation.lng : this.lng,
company_latitude: this.userLocation ? this.userLocation.lat : this.lat,
page: this.currentPage,
page_size: this.pageSize
}
const res = await this.$u.api.schoolmateCompany(params)
console.log(res)
if (res && res.data) {
// 过滤掉没有经纬度的数据
const validCompanies = res.data.filter(item =>
item.company_longitude && item.company_latitude
)
// 添加到公司列表
this.companies.push(...validCompanies)
// 更新地图标记点
this.updateMarkers()
// 根据 last_page 判断是否还有更多数据
if (res.last_page && this.currentPage >= res.last_page) {
this.hasMore = false
}
console.log(`${this.currentPage}页数据加载成功,共${validCompanies.length}条,总页数:${res.last_page}`)
}
} catch (error) {
console.error('加载校友数据失败:', error)
uni.showToast({
title: '加载数据失败',
icon: 'none'
})
} finally {
this.isDataLoading = false
}
},
// 更新地图标记点
updateMarkers() {
// 创建标准的地图标记点数组
this.mapMarkers = this.companies.map((item, index) => ({
id: item.id || `marker_${index}`,
longitude: parseFloat(item.company_longitude),
latitude: parseFloat(item.company_latitude),
iconPath: this.base.imgHost('home-marker.png'), // 使用现有的地图标记图标
width: 20,
height: 20,
// callout: {
// content: item.company_name || item.name || '校友公司',
// color: '#000000',
// fontSize: 14,
// borderRadius: 4,
// bgColor: '#ffffff',
// padding: 8,
// display: 'ALWAYS'
// }
}))
console.log('更新地图标记点:', this.mapMarkers)
console.log('标记点数量:', this.mapMarkers.length)
console.log('标记点ID列表:', this.mapMarkers.map(m => m.id))
},
// 地图区域变化事件
onRegionChange(e) {
console.log('地图区域变化:', e)
// 如果是拖动地图,加载下一页数据
if (e.type === 'end' && this.hasMore && !this.isDataLoading) {
this.currentPage++
this.loadCompanyData()
}
},
// 地图点击事件(备选)
onMapTap(e) {
console.log('地图点击事件:', e)
},
// 显示公司详情
showCompanyDetail(e) {
console.log('点击标记点事件:', e)
console.log('当前公司数据:', this.companies)
const markerId = e.markerId
console.log('点击的标记点ID:', markerId)
const company = this.companies.find(item => item.id == markerId)
console.log('找到的公司:', company)
if (company) {
this.selectedCompany = company
this.showCompanyInfo = true
console.log('设置选中公司:', this.selectedCompany)
console.log('显示公司信息:', this.showCompanyInfo)
} else {
console.warn('未找到对应的公司数据')
console.warn('所有公司ID:', this.companies.map(c => c.id))
}
},
// 关闭公司详情
closeCompanyDetail() {
this.showCompanyInfo = false
this.selectedCompany = null
},
// 计算两点之间的距离(单位:公里)
getDistance(lat1, lon1) {
if (!lat1 || !lon1) return 'N/A'
const R = 6371; // 地球半径,单位公里
const dLat = (lat1 - this.lat) * Math.PI / 180;
const dLon = (lon1 - this.lng) * Math.PI / 180;
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(this.lat * Math.PI / 180) * Math.cos(lat1 * Math.PI / 180) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c; // 距离,单位公里
return distance.toFixed(2);
},
// 测试加载数据
testLoadData() {
this.currentPage = 1 // 重置页码
this.hasMore = true // 重置是否有更多数据
this.loadCompanyData()
},
// 测试显示公司详情
testShowCompanyDetail() {
if (this.companies.length > 0) {
const company = this.companies[0];
this.selectedCompany = company;
this.showCompanyInfo = true;
console.log('显示公司详情:', company);
} else {
console.warn('没有公司数据可显示');
uni.showToast({
title: '请先加载数据',
icon: 'none'
});
}
}
}
}
</script>
<style lang="scss" scoped>
.map-container {
width: 100%;
height: 100vh;
position: relative;
#schoolmateMap {
width: 100%;
height: 100%;
}
.company-info {
position: absolute;
bottom: 100rpx;
left: 50%;
transform: translateX(-50%);
width: 95%;
max-width: 700rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
z-index: 99;
box-shadow: -2px -3rpx 12px rgba(0, 0, 0, 0.1);
}
.company-info-content {
width: 100%;
padding: 30rpx;
box-sizing: border-box;
min-height: 120rpx;
}
.company-info-title {
width: 100%;
display: flex;
justify-content: space-between;
align-items: flex-start;
// margin-bottom: 20rpx;
gap: 20rpx;
}
.company-name {
font-size: 36rpx;
font-weight: bold;
color: #000;
flex: 1;
line-height: 1.4;
word-wrap: break-word;
white-space: normal;
padding-right: 10rpx;
}
.close-btn {
flex-shrink: 0;
margin-top: 5rpx;
}
.company-info-details {
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.company-address, .company-distance {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 10rpx;
color: #919191;
font-size: 28rpx;
}
.label {
color: #919191;
margin-right: 10rpx;
}
.value {
color: #000;
}
.company-users {
width: 100%;
display: flex;
flex-direction: column;
margin-top: 15rpx;
color: #919191;
font-size: 28rpx;
}
.users-list {
display: flex;
flex-wrap: wrap;
gap: 15rpx;
margin-top: 10rpx;
justify-content: space-between; /* 确保两个元素之间有合适的间距 */
}
.user-item {
display: flex;
flex-direction: column;
align-items: flex-start;
background: #f5f5f5;
padding: 12rpx 15rpx;
border-radius: 20rpx;
border: 1rpx solid #e0e0e0;
gap: 8rpx;
min-height: 120rpx; /* 确保卡片高度一致 */
box-sizing: border-box;
width: 47%; /* 一行显示两条数据,留出足够间距 */
flex-shrink: 0; /* 防止被压缩 */
}
.user-course {
width: 100%;
}
.course-text {
color: #666;
font-size: 20rpx;
line-height: 1.3;
word-wrap: break-word;
white-space: normal;
display: block;
min-height: 52rpx; /* 确保高度一致,约等于两行文字的高度 */
}
.user-info {
display: flex;
align-items: center;
width: 100%;
}
.user-name {
color: #000;
font-weight: bold;
font-size: 26rpx;
}
.user-position {
color: #919191;
font-size: 22rpx;
margin-left: 5rpx;
}
.location-tip {
position: absolute;
left: 50%;
bottom: 200rpx;
transform: translateX(-50%);
width: 80%;
z-index: 99;
text-align: center;
background: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 20rpx 30rpx;
border-radius: 40rpx;
font-size: 28rpx;
}
.loading-tip {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: 99;
background: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 20rpx 30rpx;
border-radius: 20rpx;
font-size: 28rpx;
}
.data-loading {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: 99;
background: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 30rpx;
border-radius: 20rpx;
font-size: 28rpx;
display: flex;
flex-direction: column;
align-items: center;
gap: 20rpx;
text {
color: #fff;
}
}
.debug-info {
position: absolute;
top: 20rpx;
left: 20rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 10rpx 20rpx;
border-radius: 20rpx;
font-size: 24rpx;
}
.test-btn {
position: absolute;
bottom: 200rpx;
left: 50%;
transform: translateX(-50%);
z-index: 99;
background: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 20rpx 40rpx;
border-radius: 40rpx;
font-size: 28rpx;
border: 1rpx solid #fff;
}
}
</style>