fix:修复bug

This commit is contained in:
2025-12-10 15:16:47 +08:00
parent 8dd95a325b
commit be0eab5460
10 changed files with 1463 additions and 984 deletions
+131 -41
View File
@@ -7,23 +7,24 @@
</view>
</view>
<!-- 顶部信息区域通知招商等 -->
<view class="top-info-section" :style="{ top: (statusBarHeight + navBarHeight) + 'px' }">
<!-- 通知栏 -->
<view class="notice-wrapper" v-if="noticeText" @click="openNoticePopup">
<uv-notice-bar :text="noticeText" :speed="50" :show-icon="true" color="#07c160" bg-color="#E8F8EF"
icon="volume"></uv-notice-bar>
</view>
<!-- 顶部信息区域通知招商等 -->
<view class="top-info-section" :style="{ top: (statusBarHeight + navBarHeight) + 'px' }">
<!-- 通知栏 -->
<view class="notice-wrapper" v-if="noticeText" @click="openNoticePopup">
<uv-notice-bar :text="noticeText" :speed="50" :show-icon="true" color="#07c160" bg-color="#E8F8EF"
icon="volume"></uv-notice-bar>
</view>
</view>
<!-- 内容区域 -->
<view class="main-content" :style="{ paddingTop: (statusBarHeight + navBarHeight + noticeHeight) + 'px' }">
<!-- 全屏地图组件 -->
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
:enableMarkers="true" :hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup"
@relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
@mapCenterChange="onMapCenterChange" />
<!-- 全屏地图组件 -->
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
:enableMarkers="true" :bannerImages="bannerImages"
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup"
@relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
@mapCenterChange="onMapCenterChange" @bannerClick="handleBannerClick" />
<!-- 地图加载状态 -->
<view v-if="isLoading || !userLocation" class="map-loading-placeholder">
@@ -200,7 +201,6 @@
getPotionsDetail
} from '../../config/api/order.js'
import {
getNoticeTextData,
getActiveActivity
} from '../../config/api/system.js'
// 导入地图工具函数
@@ -291,27 +291,112 @@
}
const noticeText = ref('')
const bannerImages = ref([]) // 首页广告图片列表
// 将语言代码转换为后端接受的格式
const convertLanguageCode = (lang) => {
// zh-CN -> zh_CN (转换下划线)
// en-US -> en_US (转换下划线)
return lang.replace(/-/g, '_')
}
// 获取公告内容(支持多语言)
const getNoticeText = async () => {
const parasm = {
'title': '用户端公告'
}
const res = await getNoticeTextData(parasm);
noticeText.value = res.data.noticeContent;
// 设置通知栏高度
if (res.data.noticeContent) {
noticeHeight.value = 50 // 通知栏高度约50px
}
// 将通知内容存储到本地缓存
try {
uni.setStorageSync('noticeContent', res.data.noticeContent);
console.log('通知内容已缓存:', res.data.noticeContent);
} catch (e) {
console.warn('缓存通知内容失败:', e);
// 获取当前语言设置
const currentLang = uni.getStorageSync('language') || 'zh-CN'
const languageCode = convertLanguageCode(currentLang)
console.log('加载公告,语言:', currentLang, '转换后:', languageCode)
// 调用接口获取公告内容
const res = await uni.request({
url: `${URL}/device/announcementConfig/current`,
method: 'GET',
header: {
'Content-Language': languageCode
},
data: {
type: 'wx_user_type' // 微信小程序用户端
}
})
console.log('公告响应:', res)
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
// 使用后端自动解析的 announcement 字段
const announcement = res.data.data.announcement || ''
noticeText.value = announcement
// 设置通知栏高度
if (announcement) {
noticeHeight.value = 50 // 通知栏高度约50px
}
// 将通知内容存储到本地缓存
try {
uni.setStorageSync('noticeContent', announcement)
console.log('通知内容已缓存:', announcement)
} catch (e) {
console.warn('缓存通知内容失败:', e)
}
} else {
console.warn('获取公告失败:', res.data?.msg || '未知错误')
}
} catch (error) {
console.error('获取公告失败:', error)
}
}
// 获取首页广告图片(支持多语言)
const getBannerImages = async () => {
try {
// 获取当前语言设置
const currentLang = uni.getStorageSync('language') || 'zh-CN'
const languageCode = convertLanguageCode(currentLang)
console.log('加载首页广告,语言:', currentLang, '转换后:', languageCode)
// 调用接口获取广告内容
const res = await uni.request({
url: `${URL}/device/advertisementConfig/current`,
method: 'GET',
header: {
'Content-Language': languageCode
},
data: {
appPlatform: 'wechat', // 微信平台
appType: 'user' // 用户端
}
})
console.log('首页广告响应:', res)
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
// 使用 files 字段(图片列表)
const files = res.data.data.files || []
if (files.length > 0) {
bannerImages.value = files
console.log('首页广告加载成功,图片数量:', files.length)
} else {
console.warn('未获取到广告图片')
}
} else {
console.warn('获取首页广告失败:', res.data?.msg || '未知错误')
}
} catch (error) {
console.error('获取首页广告失败:', error)
}
}
// 处理首页广告点击
const handleBannerClick = (index) => {
console.log('点击首页广告:', index, bannerImages.value[index])
// 可以根据需要添加跳转逻辑
// 例如跳转到合作加盟页面
uni.navigateTo({ url: '/pages/join/index' })
}
// 查询最近的活动
const checkActiveActivity = async () => {
try {
@@ -438,20 +523,25 @@
console.warn('清理旧缓存失败:', e);
}
// 开发环境测试距离计算
if (process.env.NODE_ENV === 'development') {
testDistanceCalculation()
}
await getNoticeText();
// 开发环境测试距离计算
if (process.env.NODE_ENV === 'development') {
testDistanceCalculation()
}
// 并行加载公告和广告(不依赖定位)
await Promise.all([
getNoticeText(),
getBannerImages()
])
// 1. 先获取用户位置
await getUserLocationAndAddress()
// 1. 先获取用户位置
await getUserLocationAndAddress()
// 2. 加载场地列表(依赖定位)
await loadPositions()
// 2. 加载场地列表(依赖定位)
await loadPositions()
// 3. 查询活动并显示弹窗
await checkActiveActivity()
// 3. 查询活动并显示弹窗
await checkActiveActivity()
} catch (error) {
console.error('初始化失败:', error)
+141 -34
View File
@@ -1,40 +1,118 @@
<template>
<view class="loading-page">
<!-- 加载状态 -->
<view v-if="loading" class="loading-page">
<view class="loading-content">
<view class="loading-spinner"></view>
<text>{{ $t('common.loading') }}</text>
</view>
</view>
<!-- 错误状态 -->
<view v-else-if="error" class="error-page">
<view class="error-content">
<text class="error-icon"></text>
<text class="error-message">{{ errorMessage }}</text>
<button class="retry-btn" @click="loadAgreement">{{ $t('common.retry') }}</button>
</view>
</view>
<!-- 内容显示 -->
<view v-else class="legal-page">
<view class="header">
<text class="title">{{ agreementData.title || $t('legal.agreement') }}</text>
<text v-if="agreementData.remark" class="subtitle">{{ agreementData.remark }}</text>
</view>
<scroll-view class="content" scroll-y>
<rich-text :nodes="agreementData.content"></rich-text>
</scroll-view>
<view class="footer">
<text>{{ $t('legal.footerNotice') }}</text>
</view>
</view>
</template>
<script setup>
import { onMounted } from 'vue'
import { ref, onMounted } from 'vue'
import { useI18n } from '@/utils/i18n.js'
import { URL } from '@/config/url.js'
const { t: $t } = useI18n()
onMounted(() => {
// 获取当前语言设置
const currentLang = uni.getStorageSync('language') || 'zh-CN'
// 根据语言跳转到对应页面
const targetPage = currentLang === 'en-US'
? '/pages/legal/agreement-en'
: '/pages/legal/agreement-zh'
console.log('当前语言:', currentLang, '跳转到:', targetPage)
// 使用 redirectTo 替换当前页面
uni.redirectTo({
url: targetPage,
fail: (err) => {
console.error('跳转失败:', err)
// 如果跳转失败,默认跳转到中文版
uni.redirectTo({
url: '/pages/legal/agreement-zh'
// 响应式数据
const loading = ref(true)
const error = ref(false)
const errorMessage = ref('')
const agreementData = ref({
title: '',
content: '',
remark: ''
})
// 将语言代码转换为后端接受的格式
const convertLanguageCode = (lang) => {
// zh-CN -> zh-CN (保持不变)
// en-US -> en_US (转换下划线)
return lang.replace(/-/g, '_')
}
// 加载协议内容
const loadAgreement = async () => {
loading.value = true
error.value = false
errorMessage.value = ''
try {
// 获取当前语言设置
const currentLang = uni.getStorageSync('language') || 'zh-CN'
const languageCode = convertLanguageCode(currentLang)
console.log('加载用户协议,语言:', currentLang, '转换后:', languageCode)
// 调用接口获取协议内容
const res = await uni.request({
url: `${URL}/device/agreementConfig/current`,
method: 'GET',
header: {
'Content-Language': languageCode,
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
},
data: {
agreementCode: 'USER_AGREEMENT',
appPlatform: 'wechat',
appType: 'user'
}
})
console.log('用户协议响应:', res)
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
agreementData.value = {
title: res.data.data.title || $t('legal.agreement'),
content: res.data.data.content || '',
remark: res.data.data.remark || ''
}
// 设置页面标题
uni.setNavigationBarTitle({
title: agreementData.value.title
})
} else {
throw new Error(res.data.msg || $t('common.loadFailed'))
}
})
} catch (err) {
console.error('加载用户协议失败:', err)
error.value = true
errorMessage.value = err.message || $t('common.loadFailed')
} finally {
loading.value = false
}
}
onMounted(() => {
loadAgreement()
})
</script>
@@ -67,10 +145,41 @@
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
text {
font-size: 28rpx;
color: #666;
.error-page {
min-height: 100vh;
background: #f8f8f8;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
}
.error-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 24rpx;
.error-icon {
font-size: 80rpx;
}
.error-message {
font-size: 28rpx;
color: #666;
text-align: center;
}
.retry-btn {
margin-top: 20rpx;
padding: 20rpx 60rpx;
background: #07c160;
color: #fff;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
}
}
.legal-page {
@@ -83,33 +192,31 @@
.header {
margin-bottom: 16rpx;
.title {
font-size: 40rpx;
font-weight: 600;
color: #222;
margin-bottom: 8rpx;
display: block;
}
.subtitle {
font-size: 24rpx;
color: #888;
display: block;
}
}
.content {
// width: 100%;
background: #fff;
border-radius: 16rpx;
padding: 16rpx 20rpx;
padding: 20rpx;
flex: 1;
min-height: 0;
box-sizing: border-box;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}
.h1 { font-size: 30rpx; font-weight: 600; color: #222; margin: 18rpx 0 12rpx; }
.p { font-size: 26rpx; color: #444; line-height: 1.8; margin-bottom: 10rpx; }
.bold { font-weight: 600; color: #222; }
.footer {
text-align: center;
margin-top: 16rpx;
+148 -68
View File
@@ -1,40 +1,118 @@
<template>
<view class="loading-page">
<!-- 加载状态 -->
<view v-if="loading" class="loading-page">
<view class="loading-content">
<view class="loading-spinner"></view>
<text>{{ $t('common.loading') }}</text>
</view>
</view>
<!-- 错误状态 -->
<view v-else-if="error" class="error-page">
<view class="error-content">
<text class="error-icon"></text>
<text class="error-message">{{ errorMessage }}</text>
<button class="retry-btn" @click="loadAgreement">{{ $t('common.retry') }}</button>
</view>
</view>
<!-- 内容显示 -->
<view v-else class="legal-page">
<view class="header">
<text class="title">{{ agreementData.title || $t('legal.privacy') }}</text>
<text v-if="agreementData.remark" class="subtitle">{{ agreementData.remark }}</text>
</view>
<scroll-view class="content" scroll-y>
<rich-text :nodes="agreementData.content"></rich-text>
</scroll-view>
<view class="footer">
<text>{{ $t('legal.footerNoticePolicy') }}</text>
</view>
</view>
</template>
<script setup>
import { onMounted } from 'vue'
import { ref, onMounted } from 'vue'
import { useI18n } from '@/utils/i18n.js'
import { URL } from '@/config/url.js'
const { t: $t } = useI18n()
onMounted(() => {
// 获取当前语言设置
const currentLang = uni.getStorageSync('language') || 'zh-CN'
// 根据语言跳转到对应页面
const targetPage = currentLang === 'en-US'
? '/pages/legal/privacy-en'
: '/pages/legal/privacy-zh'
console.log('当前语言:', currentLang, '跳转到:', targetPage)
// 使用 redirectTo 替换当前页面
uni.redirectTo({
url: targetPage,
fail: (err) => {
console.error('跳转失败:', err)
// 如果跳转失败,默认跳转到中文版
uni.redirectTo({
url: '/pages/legal/privacy-zh'
// 响应式数据
const loading = ref(true)
const error = ref(false)
const errorMessage = ref('')
const agreementData = ref({
title: '',
content: '',
remark: ''
})
// 将语言代码转换为后端接受的格式
const convertLanguageCode = (lang) => {
// zh-CN -> zh-CN (保持不变)
// en-US -> en_US (转换下划线)
return lang.replace(/-/g, '_')
}
// 加载协议内容
const loadAgreement = async () => {
loading.value = true
error.value = false
errorMessage.value = ''
try {
// 获取当前语言设置
const currentLang = uni.getStorageSync('language') || 'zh-CN'
const languageCode = convertLanguageCode(currentLang)
console.log('加载隐私政策,语言:', currentLang, '转换后:', languageCode)
// 调用接口获取协议内容
const res = await uni.request({
url: `${URL}/device/agreementConfig/current`,
method: 'GET',
header: {
'Content-Language': languageCode,
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
},
data: {
agreementCode: 'PRIVACY_POLICY',
appPlatform: 'wechat',
appType: 'user'
}
})
console.log('隐私政策响应:', res)
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
agreementData.value = {
title: res.data.data.title || $t('legal.privacy'),
content: res.data.data.content || '',
remark: res.data.data.remark || ''
}
// 设置页面标题
uni.setNavigationBarTitle({
title: agreementData.value.title
})
} else {
throw new Error(res.data.msg || $t('common.loadFailed'))
}
})
} catch (err) {
console.error('加载隐私政策失败:', err)
error.value = true
errorMessage.value = err.message || $t('common.loadFailed')
} finally {
loading.value = false
}
}
onMounted(() => {
loadAgreement()
})
</script>
@@ -67,10 +145,41 @@
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
text {
font-size: 28rpx;
color: #666;
.error-page {
min-height: 100vh;
background: #f8f8f8;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
}
.error-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 24rpx;
.error-icon {
font-size: 80rpx;
}
.error-message {
font-size: 28rpx;
color: #666;
text-align: center;
}
.retry-btn {
margin-top: 20rpx;
padding: 20rpx 60rpx;
background: #07c160;
color: #fff;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
}
}
.legal-page {
@@ -83,60 +192,31 @@
.header {
margin-bottom: 16rpx;
}
.title {
font-size: 40rpx;
font-weight: 600;
color: #222;
margin-bottom: 8rpx;
}
.title {
font-size: 40rpx;
font-weight: 600;
color: #222;
margin-bottom: 8rpx;
display: block;
}
.subtitle {
font-size: 24rpx;
color: #888;
}
.card {
background: #fff;
border-radius: 16rpx;
padding: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}
.notice {
margin-bottom: 16rpx;
.subtitle {
font-size: 24rpx;
color: #888;
display: block;
}
}
.content {
background: #fff;
border-radius: 16rpx;
padding: 16rpx 20rpx;
padding: 20rpx;
flex: 1;
min-height: 0;
box-sizing: border-box;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}
.h1 {
font-size: 30rpx;
font-weight: 600;
color: #222;
margin: 18rpx 0 12rpx;
}
.p {
font-size: 26rpx;
color: #444;
line-height: 1.8;
margin-bottom: 10rpx;
}
.bold {
font-weight: 600;
color: #222;
}
.footer {
text-align: center;
margin-top: 16rpx;
+76 -4
View File
@@ -23,10 +23,21 @@
</view>
</view> -->
<view class="section">
<view class="banner-card" @click="navigateTo('/pages/join/index')">
<image class="banner-image" src="/static/userCenter_swiper.png" mode="aspectFill"></image>
</view>
<view class="section">
<!-- 广告轮播 -->
<view class="banner-card" v-if="bannerImages.length > 0">
<swiper class="banner-swiper" :indicator-dots="bannerImages.length > 1"
:autoplay="bannerImages.length > 1" :circular="true" :interval="3000">
<swiper-item v-for="(image, index) in bannerImages" :key="index">
<image class="banner-image" :src="image" mode="aspectFill"
@click="handleBannerClick(index)"></image>
</swiper-item>
</swiper>
</view>
<!-- 默认图片(当没有广告时显示) -->
<view class="banner-card" v-else @click="navigateTo('/pages/join/index')">
<image class="banner-image" src="/static/userCenter_swiper.png" mode="aspectFill"></image>
</view>
<!-- <view class="section-title">常用服务</view> -->
<view class="list">
<view class="list-item" @click="handleQuickReturn">
@@ -147,6 +158,60 @@ import {
const appVersion = ref('1.0.0');
const showMenuItem = ref(false)
const bannerImages = ref([]) // 广告图片列表
// 将语言代码转换为后端接受的格式
const convertLanguageCode = (lang) => {
// zh-CN -> zh_CN (转换下划线)
// en-US -> en_US (转换下划线)
return lang.replace(/-/g, '_')
}
// 获取广告图片
const getBannerImages = async () => {
try {
// 获取当前语言设置
const currentLang = uni.getStorageSync('language') || 'zh-CN'
const languageCode = convertLanguageCode(currentLang)
console.log('加载个人中心广告,语言:', currentLang, '转换后:', languageCode)
// 调用接口获取广告内容
const res = await uni.request({
url: `${URL}/device/advertisementConfig/current`,
method: 'GET',
header: {
'Content-Language': languageCode
},
data: {
appPlatform: 'wechat', // 微信平台
appType: 'user' // 用户端
}
})
console.log('个人中心广告响应:', res)
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
// 使用 files 字段(图片列表)
const files = res.data.data.files || []
if (files.length > 0) {
bannerImages.value = files
console.log('个人中心广告加载成功,图片数量:', files.length)
}
} else {
console.warn('获取个人中心广告失败:', res.data?.msg || '未知错误')
}
} catch (error) {
console.error('获取个人中心广告失败:', error)
}
}
// 处理广告点击
const handleBannerClick = (index) => {
console.log('点击广告:', index)
// 可以根据需要添加跳转逻辑
// 例如:navigateTo('/pages/join/index')
}
// 页面加载时初始化
onMounted(() => {
@@ -155,11 +220,13 @@ import {
})
getInfo();
initVersion();
getBannerImages(); // 加载广告
});
// 页面显示时刷新用户信息
onShow(() => {
getInfo();
getBannerImages(); // 刷新广告
});
// 获取用户信息
@@ -571,6 +638,11 @@ import {
border: 1rpx solid #f0f0f0;
}
.banner-swiper {
width: 100%;
height: 260rpx;
}
.banner-image {
width: 100%;
height: 260rpx;
+804 -815
View File
File diff suppressed because it is too large Load Diff