修改互助详情评论列表

This commit is contained in:
qiuyuan 2025-07-28 18:51:47 +08:00
parent a2dda03fdb
commit 68354f01d4
3 changed files with 366 additions and 167 deletions

View File

@ -113,12 +113,22 @@
<u-icon name="map-fill" color="#fff" size="28"></u-icon> <u-icon name="map-fill" color="#fff" size="28"></u-icon>
<text>导航前往</text> <text>导航前往</text>
</button> </button>
<button class="share-button" @click="handleShare"> <button class="share-button" open-type="share" @click="handleShareClick">
<u-icon name="share-square" color="#8dbafc" size="28"></u-icon> <u-icon name="share-square" color="#8dbafc" size="28"></u-icon>
<text>分享</text> <text>分享</text>
</button> </button>
</view> </view>
</view> </view>
<!-- 授权弹窗 -->
<u-modal
v-model="showLocationModal"
title="位置授权提示"
:content="locationModalContent"
show-cancel-button
@confirm="handleAuthConfirm"
@cancel="handleAuthCancel"
></u-modal>
</view> </view>
</template> </template>
@ -158,6 +168,10 @@ export default {
status: 1 status: 1
}, },
local: null, local: null,
showLocationModal: false,
locationModalContent: '我们需要获取您的位置信息,以便提供更精准的服务',
userLocation: null,
isRequestingLocation: false
} }
}, },
computed: { computed: {
@ -188,10 +202,17 @@ export default {
} }
}, },
onLoad(options) { onLoad(options) {
if (options && options.Id && options.local) { if (options?.Id) {
this.Id = options.Id; this.Id = options.Id;
this.local = options.local; this.local = options.local || null;
this.getAroundDetail();
} }
//
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
});
}, },
mounted() { mounted() {
this.getAroundDetail(); this.getAroundDetail();
@ -207,26 +228,147 @@ export default {
}, },
async getAroundDetail() { async getAroundDetail() {
try { try {
const res = await get(`/api/v1/apps/surrounding/${this.Id}`); const res = await get(`/api/v1/apps/surrounding/${this.Id}`);
if (!res || !res.success) { if (res?.success) {
throw new Error('获取详情失败'); this.detailInfo = {
} ...this.detailInfo,
...res.data,
if (res.data.storeCover) { storeCover: res.data.storeCover?.startsWith('http')
res.data.storeCover = res.data.storeCover.startsWith('http') ? res.data.storeCover : IMAGE_BASE_URL + res.data.storeCover; ? res.data.storeCover
} : IMAGE_BASE_URL + res.data.storeCover
};
this.detailInfo = {...this.detailInfo, ...res.data}; }
} catch (err) { } catch (error) {
console.error('获取详情失败:', err); console.error('获取详情失败:', error);
uni.showToast({ uni.showToast({ title: '获取详情失败', icon: 'none' });
title: '获取详情失败', }
icon: 'none'
});
}
}, },
//
async handleShareClick() {
this.isRequestingLocation = true;
try {
await this.checkLocationPermission();
} catch (error) {
console.error('位置授权异常:', error);
} finally {
this.isRequestingLocation = false;
}
},
//
async checkLocationPermission() {
const status = await this.getPermissionStatus();
if (status === 'granted') {
await this.getUserLocation();
return;
}
if (status === 'none') {
//
this.requestLocationPermission();
} else {
//
this.showLocationModal = true;
}
},
//
getPermissionStatus() {
return new Promise((resolve) => {
uni.getSetting({
success: (res) => {
if (res.authSetting['scope.userLocation'] === undefined) {
resolve('none');
} else if (res.authSetting['scope.userLocation']) {
resolve('granted');
} else {
resolve('denied');
}
},
fail: () => resolve('none')
});
});
},
//
requestLocationPermission() {
uni.authorize({
scope: 'scope.userLocation',
success: () => this.getUserLocation(),
fail: (err) => {
console.error('授权失败:', err);
this.showLocationModal = true;
}
});
},
//
getUserLocation() {
return new Promise((resolve, reject) => {
uni.getLocation({
type: 'wgs84',
success: (res) => {
this.userLocation = {
latitude: res.latitude,
longitude: res.longitude
};
resolve(res);
},
fail: (err) => {
console.error('获取位置失败:', err);
reject(err);
}
});
});
},
//
handleAuthConfirm() {
uni.openSetting({
success: (res) => {
if (res.authSetting['scope.userLocation']) {
this.getUserLocation().catch(() => {
uni.showToast({ title: '获取位置失败', icon: 'none' });
});
}
this.showLocationModal = false;
}
});
},
//
handleAuthCancel() {
this.showLocationModal = false;
uni.showToast({ title: '已取消位置授权', icon: 'none' });
},
//
onShareAppMessage() {
return {
title: this.detailInfo.storeName || '发现一个好地方',
path: `/pages/surrounding/detail?Id=${this.Id}`,
imageUrl: this.detailInfo.storeCover,
success: () => {
this.logShareEvent();
},
fail: (err) => {
console.error('分享失败:', err);
}
};
},
//
onShareTimeline() {
return {
title: this.detailInfo.storeName || '发现一个好地方',
query: `Id=${this.Id}`,
imageUrl: this.detailInfo.storeCover
};
},
openMap() { openMap() {
const { latitude, longitude, storeName, storeAddress } = this.detailInfo; const { latitude, longitude, storeName, storeAddress } = this.detailInfo;
if (latitude && longitude) { if (latitude && longitude) {

View File

@ -1,17 +1,20 @@
<template> <template>
<view class="container"> <view class="container">
<view v-for="(item, index) in list" :key="index" class="shop-card" @click="goPage('aroundDetail')"> <view v-for="(item, index) in list" :key="index" class="shop-card" @click="goDetail(item.id,item.distance)">
<u-cell :border="false" class="custom-cell"> <u-cell :border="false" class="custom-cell">
<image slot="icon" :src="item.image" mode="aspectFill" class="cell-image"></image> <image slot="icon" :src="`${IMAGE_BASE_URL}`+item.storeCover" mode="aspectFill" class="cell-image"></image>
<view slot="title" class="cell-right"> <view slot="title" class="cell-right">
<view class="shop-name">{{ item.name }}</view> <view class="shop-name">{{ item.storeName }}</view>
<view class="shop-info"> <view class="shop-info">
<!-- <text> {{ item.rating }} </text> --> <text class="price">{{ item.price > 0 ? `人均¥${item.price}` : '免费开放' }}</text>
<text>人均¥{{ item.perCapita }}</text> <text class="distance">{{ formatDistance(item.distance) }}</text>
<text class="distance">直线{{ item.distance }}m</text>
</view> </view>
<view class="desc-container"> <view class="shop-desc" v-if="item.content">
<text class="desc">{{ "“" + item.desc + "”" }}</text> <text>{{ truncateContent(item.content) }}</text>
</view>
<view class="open-time" v-if="item.openAt">
<u-icon name="clock" size="24" color="#8a8a8a"></u-icon>
<text>开放时间{{ item.openAt }}</text>
</view> </view>
</view> </view>
</u-cell> </u-cell>
@ -20,128 +23,173 @@
</template> </template>
<script> <script>
import { get, post } from '@/utils/request';
import { IMAGE_BASE_URL, BASE_URL } from '@/utils/config';
export default { export default {
data() { data() {
return { return {
list: [{ IMAGE_BASE_URL,
image: "/static/imgs/service/hema.png", // static Id: null,
name: '肯德基(南通紫琅店)', latitude: null,
rating: 4.8, longitude: null,
monthSales: 4683, list: []
perCapita: 30,
distance: 221,
desc: '超棒,同学们都说好吃'
},
{
image: "/static/imgs/service/hema.png",
name: '汉堡王(南通紫琅店)',
rating: 4.8,
monthSales: 4683,
perCapita: 30,
distance: 221,
desc: '超棒,同学们都说好吃'
},
{
image: "/static/imgs/service/hema.png",
name: '瑞幸咖啡(南通紫琅店)',
rating: 4.8,
monthSales: 4683,
perCapita: 30,
distance: 221,
desc: '超棒,同学们都说不错'
},
{
image: "/static/imgs/service/hema.png",
name: '绿茶餐厅',
rating: 4.8,
monthSales: 4683,
perCapita: 30,
distance: 221,
desc: '超棒,同学们都说好吃'
}
]
}; };
}, },
onLoad() { onLoad(options) {
if (options && options.Id && options.latitude && options.longitude) {
this.Id = options.Id;
this.longitude = options.longitude;
this.latitude = options.latitude;
}
},
mounted() {
this.getAroundList();
}, },
methods: { methods: {
// async getAroundList() {
goPage(page) { let params = {
console.log("==进来", page) current: 1,
uni.navigateTo({ pageSize: 100,
url: `/pages/${page}/index`, longitude: this.longitude,
success: () => { latitude: this.latitude,
console.log('切换到tabBar页面成功'); typeId: this.Id,
}, }
fail: (err) => { try {
console.error('切换到tabBar页面失败:', err); const res = await get('/api/v1/apps/surrounding', params);
if (!res || !res.success) {
throw new Error('获取列表失败');
} }
this.list = res.data || [];
} catch (err) {
console.error('获取列表失败:', err);
uni.showToast({
title: '加载失败',
icon: 'none'
});
}
},
goDetail(id, local) {
uni.navigateTo({
url: `/pages/aroundDetail/index?Id=${id}&local=${local}`,
}); });
}, },
formatDistance(distance) {
if (distance >= 1000) {
return `距离${(distance / 1000).toFixed(1)}km`;
}
return `距离${Math.round(distance)}m`;
},
truncateContent(content) {
if (content.length > 60) {
return content.substring(0, 60) + '...';
}
return content;
}
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.container { .container {
padding: 10px; padding: 20rpx;
background-color: #f8f9fa;
min-height: 100vh;
}
.shop-card { .shop-card {
margin-bottom: 15px; margin-bottom: 24rpx;
border-radius: 10px; border-radius: 16rpx;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08); background-color: #fff;
background-color: #fff; box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
overflow: hidden;
transition: all 0.2s ease;
&:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
}
.custom-cell {
padding: 0;
}
.cell-image {
width: 240rpx;
height: 240rpx;
flex-shrink: 0;
background-color: #f5f5f5;
}
.cell-right {
padding: 24rpx;
flex: 1;
}
.shop-name {
font-size: 32rpx;
font-weight: 600;
color: #2c3e50;
margin-bottom: 12rpx;
line-height: 1.4;
}
.shop-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
font-size: 26rpx;
.price {
color: #3498db;
font-weight: 500;
background-color: rgba(52, 152, 219, 0.1);
padding: 4rpx 12rpx;
border-radius: 6rpx;
} }
.custom-cell { .distance {
color: #7f8c8d;
font-size: 24rpx;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 12px 15px;
}
.cell-image { &::before {
width: 80px; content: '';
height: 80px;
border-radius: 8px;
}
.cell-right {
display: flex;
flex-direction: column;
margin-left: 10px;
.shop-name {
font-size: 16px;
font-weight: bold;
margin-bottom: 4px;
}
.shop-info {
font-size: 12px;
color: #999;
margin-bottom: 4px;
display: flex;
flex-wrap: wrap;
.distance {
margin-left: auto;
}
}
.desc-container {
display: inline-block;
margin-top: 5px;
}
.desc {
font-size: 12px;
padding: 5px 10px;
color: rgba(128, 128, 128, 1);
background: rgba(229, 229, 229, 0.5);
border-radius: 4px;
display: inline-block; display: inline-block;
width: 24rpx;
height: 24rpx;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%237f8c8d"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg>');
background-size: contain;
background-repeat: no-repeat;
margin-right: 6rpx;
} }
} }
} }
.shop-desc {
font-size: 26rpx;
color: #555;
line-height: 1.6;
margin: 12rpx 0;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
.open-time {
display: flex;
align-items: center;
font-size: 24rpx;
color: #7f8c8d;
margin-top: 8rpx;
.u-icon {
margin-right: 8rpx;
}
}
</style> </style>

View File

@ -3,7 +3,7 @@
<view class="nearby-page"> <view class="nearby-page">
<!-- 附近美食模块 --> <!-- 附近美食模块 -->
<view class="section shadow" v-for="(item,index) in aroundList" :key="index"> <view class="section shadow" v-for="(item,index) in aroundList" :key="index">
<view class="section-header" @click="goPage('aroundList')"> <view class="section-header" @click="goPage(item.id)">
<view class="section-title">{{item.label}}</view> <view class="section-title">{{item.label}}</view>
<u-icon name="arrow-right" size="20" color="#999"></u-icon> <u-icon name="arrow-right" size="20" color="#999"></u-icon>
</view> </view>
@ -38,7 +38,9 @@
data() { data() {
return { return {
IMAGE_BASE_URL, IMAGE_BASE_URL,
aroundList:[] aroundList:[],
longitude:null,
latitude:null,
} }
}, },
onLoad() {}, onLoad() {},
@ -51,6 +53,11 @@
url: `/pages/aroundDetail/index?Id=${id}&local=${local}`, url: `/pages/aroundDetail/index?Id=${id}&local=${local}`,
}); });
}, },
goPage(id){
uni.navigateTo({
url: `/pages/aroundList/index?Id=${id}&latitude=${this.latitude}&longitude=${this.longitude}`,
});
},
formatDistance(distance) { formatDistance(distance) {
if (!distance) return '未知距离'; if (!distance) return '未知距离';
if (distance < 1000) { if (distance < 1000) {
@ -61,6 +68,8 @@
}, },
async surroundingList() { async surroundingList() {
const position = await this.getCurrentPosition(); const position = await this.getCurrentPosition();
this.latitude = position.latitude;
this.longitude = position.longitude;
let params = { let params = {
current: 1, current: 1,
pageSize: 10, pageSize: 10,