hookehuyr

fix(Activities): 优化活动详情展示和参数传递

- CheckinMap: 添加日期格式化函数,将 YYYY-MM-DD 转换为 YYYY.MM.DD 格式
- ActivitiesDetail: 添加 discount_title 字段支持,并在跳转时传递该参数
- Activities: 接收并处理 discount_title 参数,构建完整的活动 URL

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
<template>
<view class="activities-container">
<!-- WebView内容 -->
<web-view
v-if="webUrl"
:src="webUrl"
class="web-view"
@message="handleMessage"
@load="handleLoad"
@error="handleError"
></web-view>
<!-- 加载状态 -->
<view v-if="loading" class="loading-container">
<view class="loading-spinner">⏳</view>
<view class="loading-text">加载中...</view>
</view>
<!-- 错误状态 -->
<view v-if="error" class="error-container">
<view class="error-icon">⚠️</view>
<view class="error-text">页面加载失败</view>
<view class="error-buttons">
<nut-button type="primary" size="small" @click="handleRetry">重试</nut-button>
<nut-button type="default" size="small" @click="handleGoBack">返回</nut-button>
</view>
</view>
<!-- 底部导航 -->
<BottomNav />
<view class="activities-container">
<!-- WebView内容 -->
<web-view
v-if="webUrl"
:src="webUrl"
class="web-view"
@message="handleMessage"
@load="handleLoad"
@error="handleError"
></web-view>
<!-- 加载状态 -->
<view v-if="loading" class="loading-container">
<view class="loading-spinner">⏳</view>
<view class="loading-text">加载中...</view>
</view>
<!-- 错误状态 -->
<view v-if="error" class="error-container">
<view class="error-icon">⚠️</view>
<view class="error-text">页面加载失败</view>
<view class="error-buttons">
<nut-button type="primary" size="small" @click="handleRetry">重试</nut-button>
<nut-button type="default" size="small" @click="handleGoBack">返回</nut-button>
</view>
</view>
<!-- 底部导航 -->
<BottomNav />
</view>
</template>
<script setup>
......@@ -53,198 +53,202 @@ const baseUrl = ref('') // 动态获取的基础URL
/**
* 处理WebView加载完成
*/
const handleLoad = (e) => {
console.log('WebView加载完成:', e)
loading.value = false
error.value = false
const handleLoad = e => {
console.log('WebView加载完成:', e)
loading.value = false
error.value = false
}
/**
* 处理WebView加载错误
*/
const handleError = (e) => {
console.error('WebView加载错误:', e)
loading.value = false
error.value = true
const handleError = e => {
console.error('WebView加载错误:', e)
loading.value = false
error.value = true
Taro.showToast({
title: '页面加载失败',
icon: 'none'
})
Taro.showToast({
title: '页面加载失败',
icon: 'none',
})
}
/**
* 处理WebView消息
*/
const handleMessage = (e) => {
console.log('WebView消息:', e)
// 可以在这里处理来自WebView的消息
const handleMessage = e => {
console.log('WebView消息:', e)
// 可以在这里处理来自WebView的消息
}
/**
* 重试加载
*/
const handleRetry = () => {
loading.value = true
error.value = false
// 重新初始化页面数据
initPageData()
loading.value = true
error.value = false
// 重新初始化页面数据
initPageData()
}
/**
* 返回上一页
*/
const handleGoBack = () => {
Taro.navigateBack({
delta: 1
}).catch(() => {
// 如果无法返回,则跳转到首页
Taro.redirectTo({
url: '/pages/Dashboard/index'
})
Taro.navigateBack({
delta: 1,
}).catch(() => {
// 如果无法返回,则跳转到首页
Taro.redirectTo({
url: '/pages/Dashboard/index',
})
})
}
/**
* 构建包含位置参数的URL
*/
const buildUrlWithLocation = (lng, lat, openid) => {
if (lng && lat && baseUrl.value) {
const separator = baseUrl.value.includes('?') ? '&' : '?'
return `${baseUrl.value}${separator}current_lng=${lng}&current_lat=${lat}&openid=${openid}`
}
return baseUrl.value || ''
const buildUrlWithLocation = (lng, lat, openid, discount_title) => {
if (lng && lat && baseUrl.value) {
const separator = baseUrl.value.includes('?') ? '&' : '?'
return `${baseUrl.value}${separator}current_lng=${lng}&current_lat=${lat}&openid=${openid}&discount_title=${discount_title}`
}
return baseUrl.value || ''
}
/**
* 初始化页面数据
*/
const initPageData = async () => {
try {
// 获取地图URL
const mapUrlResponse = await getMapUrlAPI()
if (mapUrlResponse.code && mapUrlResponse.data?.url) {
baseUrl.value = mapUrlResponse.data.url
console.log('获取到的地图URL:', baseUrl.value)
} else {
console.error('获取地图URL失败:', mapUrlResponse.msg)
// 显示错误提示,不使用默认URL
error.value = true
loading.value = false
Taro.showToast({
title: mapUrlResponse.msg || '获取地图信息失败',
icon: 'none'
})
return
}
// 获取用户信息
const { code, data } = await getUserProfileAPI()
if (code) {
// 获取路由参数中的经纬度信息
const instance = Taro.getCurrentInstance()
const { current_lng, current_lat } = instance.router?.params || {}
console.log('接收到的位置参数:', { current_lng, current_lat })
// 处理用户信息
const openid = data?.user.openid || ''
// 构建完整的URL
webUrl.value = buildUrlWithLocation(current_lng, current_lat, openid)
console.log('最终WebView URL:', webUrl.value)
}
} catch (error) {
console.error('初始化页面数据失败:', error)
// 显示错误状态,不使用默认URL
error.value = true
loading.value = false
Taro.showToast({
title: '获取地图信息失败',
icon: 'none'
})
try {
// 获取地图URL
const mapUrlResponse = await getMapUrlAPI()
if (mapUrlResponse.code && mapUrlResponse.data?.url) {
baseUrl.value = mapUrlResponse.data.url
console.log('获取到的地图URL:', baseUrl.value)
} else {
console.error('获取地图URL失败:', mapUrlResponse.msg)
// 显示错误提示,不使用默认URL
error.value = true
loading.value = false
Taro.showToast({
title: mapUrlResponse.msg || '获取地图信息失败',
icon: 'none',
})
return
}
// 获取用户信息
const { code, data } = await getUserProfileAPI()
if (code) {
// 获取路由参数中的经纬度信息
const instance = Taro.getCurrentInstance()
const { current_lng, current_lat, discount_title } = instance.router?.params || {}
console.log('接收到的位置参数:', { current_lng, current_lat, discount_title })
// 处理用户信息
const openid = data?.user.openid || ''
// 构建完整的URL
webUrl.value = buildUrlWithLocation(current_lng, current_lat, openid, discount_title)
console.log('最终WebView URL:', webUrl.value)
}
} catch (error) {
console.error('初始化页面数据失败:', error)
// 显示错误状态,不使用默认URL
error.value = true
loading.value = false
Taro.showToast({
title: '获取地图信息失败',
icon: 'none',
})
}
}
// 页面挂载时初始化
onMounted(async () => {
console.log('活动页面WebView初始化')
await initPageData()
console.log('活动页面WebView初始化')
await initPageData()
})
</script>
<style lang="less">
.activities-container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
background-color: #fff;
position: relative;
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
background-color: #fff;
position: relative;
}
.web-view {
flex: 1;
width: 100%;
// 确保webview高度在底部导航以上
height: calc(100vh - 120rpx); // 减去底部导航的高度
flex: 1;
width: 100%;
// 确保webview高度在底部导航以上
height: calc(100vh - 120rpx); // 减去底部导航的高度
}
.loading-container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
}
.loading-spinner {
font-size: 48rpx;
margin-bottom: 16rpx;
animation: spin 1s linear infinite;
font-size: 48rpx;
margin-bottom: 16rpx;
animation: spin 1s linear infinite;
}
.loading-text {
font-size: 28rpx;
color: #666;
font-size: 28rpx;
color: #666;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.error-container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
z-index: 10;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
z-index: 10;
}
.error-icon {
font-size: 80rpx;
margin-bottom: 24rpx;
font-size: 80rpx;
margin-bottom: 24rpx;
}
.error-text {
font-size: 28rpx;
color: #666;
margin-bottom: 32rpx;
font-size: 28rpx;
color: #666;
margin-bottom: 32rpx;
}
.error-buttons {
display: flex;
gap: 24rpx;
align-items: center;
display: flex;
gap: 24rpx;
align-items: center;
}
</style>
......
<!--
* @Date: 2026-02-09
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2026-02-09
* @LastEditTime: 2026-02-09 18:55:56
* @FilePath: /lls_program/src/pages/ActivitiesDetail/index.vue
* @Description: 活动详情页面 - 完全使用 map_activity.js 新接口,支持多活动详情展示
-->
......@@ -580,7 +580,7 @@ const handleJoinActivity = async () => {
// 跳转到Activities页面,并传递位置参数
await Taro.navigateTo({
url: `/pages/Activities/index?current_lng=${userLocation.value.lng}&current_lat=${userLocation.value.lat}`,
url: `/pages/Activities/index?current_lng=${userLocation.value.lng}&current_lat=${userLocation.value.lat}&discount_title=${activityData.value.discount_title}`,
})
} catch (error) {
console.error('参加活动失败:', error)
......@@ -971,6 +971,7 @@ const transformApiDataToActivityData = apiData => {
description: `欢迎参加${apiData.title}活动!`,
rules: rules,
rewards: rewards,
discount_title: apiData.discount_title || '打卡点专属优惠',
}
}
......
......@@ -55,6 +55,23 @@ const mapList = ref([])
const loading = ref(false)
/**
* 格式化日期显示
* @description 将后端返回的 YYYY-MM-DD 格式转换为 YYYY.MM.DD 格式
* @param {string} dateStr - 原始日期字符串(如 "2026-02-28")
* @returns {string} 格式化后的日期(如 "2026.02.28")
*
* @example
* formatDate("2026-02-28") // 返回 "2026.02.28"
*/
const formatDate = dateStr => {
if (!dateStr) {
return ''
}
// 将 "-" 替换为 "."
return dateStr.replace(/-/g, '.')
}
/**
* 格式化 API 数据为页面所需格式
* @param {Array} list - API 返回的活动列表
* @returns {Array} 格式化后的活动列表
......@@ -65,7 +82,8 @@ const formatMapList = list => {
title: item.title,
// 如果 cover 为空,使用默认封面图
cover: item.cover && item.cover.trim() !== '' ? item.cover : DEFAULT_COVER,
timeRange: `${item.begin_date}~${item.end_date}`,
// 格式化日期:2026-02-28 → 2026.02.28
timeRange: `${formatDate(item.begin_date)}~${formatDate(item.end_date)}`,
activityId: item.id,
}))
}
......