402 lines
17 KiB
Vue
402 lines
17 KiB
Vue
<template>
|
||
<view class="community-list-container">
|
||
<view class="top">
|
||
<image src="https://static.hshuishang.com/communityTopImg.png" mode=""></image>
|
||
</view>
|
||
<view class="community-list">
|
||
<view class="community-item-box" v-for="(item, index) in communityList" :key="index">
|
||
<view class="community-item">
|
||
<view class="community-image" @tap="enterCommunity(item)">
|
||
<!-- 使用默认图片作为 fallback -->
|
||
<image :src="item.pic || defaultCommunityImage" mode="aspectFill"
|
||
@error="handleImageError(item)"></image>
|
||
</view>
|
||
<view class="community-info">
|
||
<view class="community-name" @tap="enterCommunity(item)">{{ item.name }}</view>
|
||
<view class="community-property">物业公司:{{ item.property || '-' }}</view>
|
||
<view class="community-distance">距我当前:{{ item.distance || '未知' }}</view>
|
||
<view class="community-buttons">
|
||
<view class="community-action-btn" @tap="navigate(item)">
|
||
<uni-icons type="paperplane-filled" size="18"></uni-icons>
|
||
<text class="btn-text">导航</text>
|
||
</view>
|
||
<view class="community-action-btn" @tap="callPhone(item)" v-if="item.property_server_phone">
|
||
<uni-icons type="phone-filled" size="18"></uni-icons>
|
||
<view class="btn-text">电话</view>
|
||
</view>
|
||
</view>
|
||
<view v-if="item.isShow" class="enter-btn" @tap="enterCommunity(item)">进入小区</view>
|
||
</view>
|
||
</view>
|
||
<view class="community-address">
|
||
<image id="local"
|
||
src="https://static.hshuishang.com/property-img-file/local_localIcon.png"
|
||
mode="aspectFill"></image>
|
||
<view class="community-address-text">{{ item.addr }}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<nav-footer :current="0" />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
request,
|
||
picUrl,
|
||
uniqueByField,
|
||
menuButtonInfo,
|
||
NavgateTo,
|
||
calculateDistance
|
||
} from "../../../utils";
|
||
import { apiArr } from "../../../api/community";
|
||
|
||
export default {
|
||
name: 'CommunityList',
|
||
data() {
|
||
return {
|
||
communityList: [], // 用于显示的列表
|
||
allCommunityList: [], // 存储所有数据的列表
|
||
currentPage: 1,
|
||
pageSize: 16,
|
||
hasMoreData: true,
|
||
isLoading: false,
|
||
tencentMapKey: '55NBZ-MUQYW-EAJRL-YIWPA-ZXCR6-4NBPP', // 腾讯地图API Key
|
||
defaultCommunityImage: 'https://static.hshuishang.com/community_no_image3.png' // 默认小区图片
|
||
};
|
||
},
|
||
methods: {
|
||
async getCommunityList() {
|
||
// 如果正在加载中,则不再请求
|
||
if (this.isLoading) {
|
||
return;
|
||
}
|
||
|
||
// 显示加载中提示
|
||
uni.showLoading({
|
||
title: '加载中...'
|
||
});
|
||
|
||
this.isLoading = true;
|
||
|
||
try {
|
||
// 获取用户当前位置
|
||
const locationData = await this.getUserLocation();
|
||
if (!locationData) {
|
||
throw new Error('无法获取用户位置');
|
||
}
|
||
|
||
const userLat = parseFloat(locationData.lat);
|
||
const userLng = parseFloat(locationData.lng);
|
||
|
||
// 获取现有小区列表
|
||
const res = await request(apiArr.getAllList, "POST", {
|
||
page_num: 1,
|
||
page_size: 9999
|
||
});
|
||
|
||
if (res && res.rows) {
|
||
// 处理现有数据,只保留距离1km以内的小区
|
||
let processedList = res.rows.map(item => {
|
||
// 处理图片路径
|
||
if (item.pic) {
|
||
item.pic = picUrl + item.pic;
|
||
}
|
||
|
||
try {
|
||
// 只有当经纬度都有效时才计算距离
|
||
if (userLat && userLng && item.lat && item.lng) {
|
||
const parkLat = parseFloat(item.lat);
|
||
const parkLng = parseFloat(item.lng);
|
||
|
||
// 使用Haversine公式计算距离(单位:千米)
|
||
const distance = calculateDistance(userLat, userLng, parkLat, parkLng);
|
||
item.distance = distance.toFixed(2) + 'km';
|
||
item.distanceValue = distance; // 保存数值型距离用于排序
|
||
}
|
||
} catch (error) {
|
||
console.error('计算距离失败:', error);
|
||
item.distanceValue = Infinity;
|
||
}
|
||
// 初始化isShow属性
|
||
item.isShow = true;
|
||
|
||
return item;
|
||
});
|
||
|
||
// 过滤出距离1km以内的数据,确保距离为0的值也能被正确保留
|
||
processedList = processedList.filter(item =>
|
||
item.distanceValue !== undefined && item.distanceValue !== null && item.distanceValue <= 1
|
||
);
|
||
|
||
// 调用腾讯地图API获取附近1km的小区(包含图片信息)
|
||
const nearbyCommunities = await this.getNearbyCommunities(userLat, userLng);
|
||
|
||
// 合并现有数据和腾讯地图API返回的数据
|
||
let mergedList = [...processedList];
|
||
|
||
if (nearbyCommunities && nearbyCommunities.length > 0) {
|
||
// 处理腾讯地图返回的数据,提取图片信息
|
||
const tencentCommunities = nearbyCommunities.map(item => {
|
||
// 计算距离
|
||
const distance = calculateDistance(userLat, userLng, item.lat, item.lng);
|
||
|
||
// 提取图片(腾讯地图POI可能包含多张图片)
|
||
let communityImage = '';
|
||
if (item.photos && item.photos.length > 0) {
|
||
// 取第一张图片
|
||
communityImage = item.photos[0].url;
|
||
}
|
||
|
||
return {
|
||
name: item.title,
|
||
addr: item.address,
|
||
lat: item.lat,
|
||
lng: item.lng,
|
||
distance: distance.toFixed(2) + 'km',
|
||
distanceValue: distance,
|
||
// 补充其他必要字段
|
||
pic: communityImage || this.defaultCommunityImage, // 使用腾讯地图图片或默认图片
|
||
property: item.extension && item.extension.property_company ? item.extension.property_company : '-',
|
||
property_server_phone: item.tel || '',
|
||
community_id: `tencent_${item.id}` // 为腾讯地图数据设置唯一ID
|
||
};
|
||
});
|
||
|
||
// 过滤腾讯地图数据,只保留那些name不在接口返回数据中的小区
|
||
// 创建一个包含接口返回数据所有name的Set
|
||
const processedNames = new Set(processedList.map(item => item.name));
|
||
|
||
// 过滤腾讯地图数据
|
||
const filteredTencentCommunities = tencentCommunities.filter(item =>
|
||
!processedNames.has(item.name)
|
||
);
|
||
|
||
// 合并数据
|
||
mergedList = [...processedList, ...filteredTencentCommunities];
|
||
|
||
// 根据community_id去重
|
||
mergedList = uniqueByField(mergedList, 'community_id');
|
||
}
|
||
|
||
// 根据距离排序,确保距离为0的值也能正确排序
|
||
mergedList.sort((a, b) => {
|
||
const distanceA = a.distanceValue !== undefined && a.distanceValue !== null ? a.distanceValue : Infinity;
|
||
const distanceB = b.distanceValue !== undefined && b.distanceValue !== null ? b.distanceValue : Infinity;
|
||
|
||
return distanceA - distanceB;
|
||
});
|
||
|
||
// 保存所有数据到allCommunityList
|
||
this.allCommunityList = mergedList;
|
||
|
||
this.currentPage = 1;
|
||
this.updateDisplayList();
|
||
}
|
||
} catch (error) {
|
||
console.error('获取社区列表失败:', error);
|
||
uni.showToast({
|
||
title: '获取数据失败',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
} finally {
|
||
this.isLoading = false;
|
||
// 隐藏加载中提示
|
||
uni.hideLoading();
|
||
}
|
||
},
|
||
|
||
// 获取用户当前位置
|
||
getUserLocation() {
|
||
return new Promise((resolve, reject) => {
|
||
try {
|
||
let locationData = uni.getStorageSync('location');
|
||
if (locationData) {
|
||
// 确保locationData是对象而不是字符串
|
||
const location = typeof locationData === 'string' ? JSON.parse(locationData) : locationData;
|
||
if (location.lat && location.lng) {
|
||
resolve(location);
|
||
return;
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('从缓存获取位置失败:', error);
|
||
}
|
||
|
||
// 如果缓存中没有有效位置,则请求新的位置
|
||
uni.getLocation({
|
||
type: 'gcj02',
|
||
altitude: true,
|
||
success: (res) => {
|
||
const location = {
|
||
lat: res.latitude,
|
||
lng: res.longitude
|
||
};
|
||
// 保存到缓存
|
||
uni.setStorageSync('location', location);
|
||
resolve(location);
|
||
},
|
||
fail: (err) => {
|
||
console.error('获取位置失败:', err);
|
||
reject(err);
|
||
}
|
||
});
|
||
});
|
||
},
|
||
|
||
// 调用腾讯地图API获取附近1km的小区(包含图片信息)
|
||
async getNearbyCommunities(lat, lng) {
|
||
try {
|
||
const keyword = '小区';
|
||
const radius = 1000; // 1km范围
|
||
const pageSize = 20;
|
||
|
||
// 使用uni.request调用腾讯地图API,增加extensions=all参数获取更多信息
|
||
return new Promise((resolve, reject) => {
|
||
uni.request({
|
||
url: 'https://apis.map.qq.com/ws/place/v1/search',
|
||
method: 'GET',
|
||
data: {
|
||
keyword: keyword,
|
||
boundary: `nearby(${lat},${lng},${radius})`,
|
||
key: this.tencentMapKey,
|
||
page_size: pageSize,
|
||
extensions: 'all' // 获取详细信息,包括图片
|
||
},
|
||
success: (res) => {
|
||
if (res.statusCode === 200 && res.data.status === 0) {
|
||
// 提取需要的数据,包括图片信息
|
||
const results = res.data.data.map(item => ({
|
||
id: item.id,
|
||
title: item.title,
|
||
address: item.address,
|
||
lat: item.location.lat,
|
||
lng: item.location.lng,
|
||
tel: item.tel || '',
|
||
photos: item.photos || [], // 提取图片数组
|
||
extension: item.extension || {}, // 提取扩展信息,可能包含物业公司
|
||
isShow: false
|
||
}));
|
||
resolve(results);
|
||
} else {
|
||
console.error('腾讯地图API请求失败:', res.data);
|
||
resolve([]);
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('腾讯地图API请求错误:', err);
|
||
resolve([]);
|
||
}
|
||
});
|
||
});
|
||
} catch (error) {
|
||
console.error('获取附近小区失败:', error);
|
||
return [];
|
||
}
|
||
},
|
||
|
||
// 图片加载失败时使用默认图片
|
||
handleImageError(item) {
|
||
item.pic = this.defaultCommunityImage;
|
||
},
|
||
|
||
// 更新显示的列表数据
|
||
updateDisplayList() {
|
||
const startIndex = 0;
|
||
const endIndex = this.currentPage * this.pageSize;
|
||
this.communityList = this.allCommunityList.slice(startIndex, endIndex);
|
||
this.hasMoreData = endIndex < this.allCommunityList.length;
|
||
},
|
||
navigate(item) {
|
||
// 实现导航功能
|
||
if (item.lat && item.lng) {
|
||
// 确保经纬度是有效的数字
|
||
const latitude = parseFloat(item.lat);
|
||
const longitude = parseFloat(item.lng);
|
||
|
||
if (!isNaN(latitude) && !isNaN(longitude)) {
|
||
uni.openLocation({
|
||
latitude: latitude,
|
||
longitude: longitude,
|
||
name: item.name || '未知小区',
|
||
address: item.addr || '',
|
||
scale: 18,
|
||
success: () => {
|
||
console.log('打开地图成功:', item.name);
|
||
},
|
||
fail: (error) => {
|
||
console.error('打开地图失败:', error);
|
||
}
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: '位置信息无效',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: '暂无位置信息',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
}
|
||
},
|
||
callPhone(item) {
|
||
if (item.property_server_phone) {
|
||
uni.makePhoneCall({
|
||
phoneNumber: item.property_server_phone,
|
||
success: () => {
|
||
},
|
||
fail: (error) => {
|
||
}
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: '暂无联系电话',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
}
|
||
},
|
||
enterCommunity(item) {
|
||
request(apiArr.checkComm, "POST", {
|
||
community_id: item.community_id,
|
||
user_id: uni.getStorageSync("userId"),
|
||
}).then((res) => {
|
||
uni.setStorageSync("is_me", res.is_me)
|
||
NavgateTo("/packages/community/index/index?item=" + JSON.stringify(item));
|
||
})
|
||
},
|
||
// 下拉加载更多
|
||
loadMore() {
|
||
if (this.hasMoreData && !this.isLoading) {
|
||
this.currentPage += 1;
|
||
this.updateDisplayList();
|
||
}
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.getCommunityList();
|
||
},
|
||
// 监听页面滚动到底部
|
||
onReachBottom() {
|
||
this.loadMore();
|
||
},
|
||
// 下拉刷新
|
||
onPullDownRefresh() {
|
||
this.currentPage = 1;
|
||
this.hasMoreData = true;
|
||
this.getCommunityList().then(() => {
|
||
uni.stopPullDownRefresh();
|
||
});
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
@import url("./index.css");
|
||
</style>
|