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
+124 -6
View File
@@ -6,9 +6,18 @@
<map id="map" class="native-map" :longitude="mapCenter.longitude" :latitude="mapCenter.latitude" <map id="map" class="native-map" :longitude="mapCenter.longitude" :latitude="mapCenter.latitude"
:markers="mapMarkers" :scale="mapZoom" :show-location="false" @regionchange="onMapRegionChange" :markers="mapMarkers" :scale="mapZoom" :show-location="false" @regionchange="onMapRegionChange"
@markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated" @error="onMapError"> @markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated" @error="onMapError">
<!-- 覆盖在地图上的可点击控件使用 cover-view 以兼容小程序原生组件层级 --> <!-- 覆盖在地图上的广告轮播使用 cover-view 以兼容小程序原生组件层级 -->
<cover-view class="index-swiper" v-if="!props.hideControls && !props.hideMapOverlays" @tap="handleJoinTap"> <cover-view class="index-swiper" v-if="!props.hideControls && !props.hideMapOverlays && currentBannerImage">
<cover-image src="/static/index_swiper.png" class="index-swiper-img" mode="aspectFit"></cover-image> <cover-image :src="currentBannerImage" class="index-swiper-img" mode="aspectFill" @tap="handleBannerTap"></cover-image>
<!-- 轮播指示器 -->
<cover-view class="banner-indicators" v-if="props.bannerImages.length > 1">
<cover-view
v-for="(img, idx) in props.bannerImages"
:key="idx"
class="indicator-dot"
:class="{ active: idx === currentBannerIndex }">
</cover-view>
</cover-view>
</cover-view> </cover-view>
<!-- 地图中心固定定位图标 --> <!-- 地图中心固定定位图标 -->
@@ -105,8 +114,12 @@
hideMapOverlays: { hideMapOverlays: {
type: Boolean, type: Boolean,
default: false // 是否隐藏地图上的覆盖层元素(如中心定位图标、轮播图等) default: false // 是否隐藏地图上的覆盖层元素(如中心定位图标、轮播图等)
},
bannerImages: {
type: Array,
default: () => [] // 广告图片列表
} }
}) })
// Emits // Emits
const emit = defineEmits([ const emit = defineEmits([
@@ -114,7 +127,8 @@
'scan', 'scan',
'showList', 'showList',
'markerTap', 'markerTap',
'mapCenterChange' 'mapCenterChange',
'bannerClick'
]) ])
// 响应式数据 // 响应式数据
@@ -126,6 +140,17 @@
const mapZoom = ref(17) const mapZoom = ref(17)
const mapMarkers = ref([]) // 用于地图组件的markers const mapMarkers = ref([]) // 用于地图组件的markers
const mapContext = ref(null) // 地图上下文 const mapContext = ref(null) // 地图上下文
const currentBannerIndex = ref(0) // 当前显示的广告索引
let bannerTimer = null // 广告轮播定时器
// 计算当前显示的广告图片
const currentBannerImage = computed(() => {
if (props.bannerImages && props.bannerImages.length > 0) {
return props.bannerImages[currentBannerIndex.value]
}
// 降级:如果没有广告,显示默认图片
return '/static/index_swiper.png'
})
// 验证坐标有效性 // 验证坐标有效性
const isValidCoordinate = (lat, lng) => { const isValidCoordinate = (lat, lng) => {
@@ -220,6 +245,26 @@
deep: true deep: true
}) })
// 监听广告图片变化,启动或停止轮播
watch(() => props.bannerImages, (newImages, oldImages) => {
console.log('广告图片变化:', newImages?.length, '张')
// 先停止旧的轮播
stopBannerRotation()
currentBannerIndex.value = 0
// 如果有多张图片,启动新的轮播
if (newImages && newImages.length > 1) {
console.log('启动广告轮播,共', newImages.length, '张图片')
// 使用 nextTick 确保 DOM 已更新
nextTick(() => {
startBannerRotation()
})
}
}, {
immediate: true,
deep: true
})
// 地图加载完成事件 // 地图加载完成事件
const onMapUpdated = () => { const onMapUpdated = () => {
isLoading.value = false isLoading.value = false
@@ -337,6 +382,44 @@ const handleSearch = () => {
}) })
} }
// 处理广告点击
const handleBannerTap = () => {
console.log('点击地图广告:', currentBannerIndex.value, currentBannerImage.value)
// 触发父组件处理点击事件
emit('bannerClick', currentBannerIndex.value)
// 默认跳转到合作加盟页面
handleJoinTap()
}
// 启动广告轮播
const startBannerRotation = () => {
// 如果只有一张或没有图片,不需要轮播
if (!props.bannerImages || props.bannerImages.length <= 1) {
console.log('图片数量不足,不启动轮播')
return
}
// 清除旧的定时器
stopBannerRotation()
console.log('开始广告轮播定时器')
// 每3秒切换一次
bannerTimer = setInterval(() => {
const nextIndex = (currentBannerIndex.value + 1) % props.bannerImages.length
console.log('轮播切换:', currentBannerIndex.value, '->', nextIndex)
currentBannerIndex.value = nextIndex
}, 3000)
}
// 停止广告轮播
const stopBannerRotation = () => {
if (bannerTimer) {
console.log('停止广告轮播')
clearInterval(bannerTimer)
bannerTimer = null
}
}
const handleScan = () => { const handleScan = () => {
emit('scan') emit('scan')
} }
@@ -364,6 +447,12 @@ const handleSearch = () => {
if (collapseRef.value) { if (collapseRef.value) {
collapseRef.value.init() collapseRef.value.init()
} }
// 初始化广告轮播
if (props.bannerImages && props.bannerImages.length > 1) {
console.log('onMounted: 初始化广告轮播')
startBannerRotation()
}
}) })
}) })
@@ -373,6 +462,8 @@ const handleSearch = () => {
clearTimeout(regionChangeTimer) clearTimeout(regionChangeTimer)
regionChangeTimer = null regionChangeTimer = null
} }
// 停止广告轮播
stopBannerRotation()
mapContext.value = null mapContext.value = null
}) })
@@ -554,15 +645,42 @@ const handleSearch = () => {
border-radius: 20rpx; border-radius: 20rpx;
z-index: 1; z-index: 1;
position: absolute; position: absolute;
// top: 10rpx;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
right: 0; right: 0;
overflow: hidden;
&-img { &-img {
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 20rpx; border-radius: 20rpx;
} }
.banner-indicators {
position: absolute;
bottom: 10rpx;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 8rpx;
z-index: 2;
.indicator-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.5);
transition: all 0.3s ease;
&.active {
width: 24rpx;
border-radius: 6rpx;
background-color: rgba(255, 255, 255, 0.9);
}
}
}
} }
</style> </style>
+4 -3
View File
@@ -1,7 +1,8 @@
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用 // export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
export const URL = "https://manager.fdzpower.com/api" //正式服务器 // export const URL = "https://manager.fdzpower.com/api" //正式服务器
// export const URL = "https://fansdev.gxfs123.com/api" //测试服务器 export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
// export const URL = "http://192.168.5.30:8080" //本地调试 // export const URL = "http://192.168.5.30:8080" //本地调试
// export const URL = "http://127.0.0.1:8080" //本地调试 // export const URL = "http://127.0.0.1:8080" //本地调试
export const appid = "wx2165f0be356ae7a9" //小程序appid export const appid = "wx2165f0be356ae7a9" //微信小程序appid
export const ZFBappid = "2021006117693332" //支付宝小程序appid
+11 -2
View File
@@ -233,7 +233,13 @@ export default {
cancelFailedContactService: 'Cancel failed, please contact customer service', cancelFailedContactService: 'Cancel failed, please contact customer service',
getOrderStatusFailed: 'Failed to get order status', getOrderStatusFailed: 'Failed to get order status',
syncSuccess: 'Status synced successfully', syncSuccess: 'Status synced successfully',
syncFailed: 'Sync failed' syncFailed: 'Sync failed',
freeRentTime: 'Free Time',
pricingRule: 'Pricing Rule',
paymentMethod: 'Payment Method',
perHour: 'per hour',
perMinute: 'per minute',
perHalfHour: 'per half hour'
}, },
user: { user: {
@@ -556,7 +562,10 @@ export default {
daysAgo: 'days ago', daysAgo: 'days ago',
yesterday: 'Yesterday', yesterday: 'Yesterday',
today: 'Today', today: 'Today',
tomorrow: 'Tomorrow' tomorrow: 'Tomorrow',
hours: 'hour(s)',
minutes: 'minute(s)',
halfHours: 'half hour(s)'
}, },
unit: { unit: {
+11 -2
View File
@@ -233,7 +233,13 @@ export default {
cancelFailedContactService: '取消订单失败,请联系客服', cancelFailedContactService: '取消订单失败,请联系客服',
getOrderStatusFailed: '订单状态查询失败', getOrderStatusFailed: '订单状态查询失败',
syncSuccess: '状态同步成功', syncSuccess: '状态同步成功',
syncFailed: '同步状态失败' syncFailed: '同步状态失败',
freeRentTime: '免费时长',
pricingRule: '计费规则',
paymentMethod: '支付方式',
perHour: '每小时',
perMinute: '每分钟',
perHalfHour: '每半小时'
}, },
user: { user: {
@@ -556,7 +562,10 @@ export default {
daysAgo: '天前', daysAgo: '天前',
yesterday: '昨天', yesterday: '昨天',
today: '今天', today: '今天',
tomorrow: '明天' tomorrow: '明天',
hours: '小时',
minutes: '分钟',
halfHours: '半小时'
}, },
unit: { unit: {
+5 -1
View File
@@ -69,7 +69,11 @@
"requiredPrivateInfos" : [ "getLocation", "chooseLocation" ] "requiredPrivateInfos" : [ "getLocation", "chooseLocation" ]
}, },
"mp-alipay" : { "mp-alipay" : {
"usingComponents" : true "usingComponents" : true,
"appid" : "2021006117693332",
"unipush" : {
"enable" : true
}
}, },
"mp-baidu" : { "mp-baidu" : {
"usingComponents" : true "usingComponents" : true
+103 -13
View File
@@ -21,9 +21,10 @@
<!-- 全屏地图组件 --> <!-- 全屏地图组件 -->
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation" <MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword" :positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
:enableMarkers="true" :hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup" :enableMarkers="true" :bannerImages="bannerImages"
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup"
@relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition" @relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
@mapCenterChange="onMapCenterChange" /> @mapCenterChange="onMapCenterChange" @bannerClick="handleBannerClick" />
<!-- 地图加载状态 --> <!-- 地图加载状态 -->
<view v-if="isLoading || !userLocation" class="map-loading-placeholder"> <view v-if="isLoading || !userLocation" class="map-loading-placeholder">
@@ -200,7 +201,6 @@
getPotionsDetail getPotionsDetail
} from '../../config/api/order.js' } from '../../config/api/order.js'
import { import {
getNoticeTextData,
getActiveActivity getActiveActivity
} from '../../config/api/system.js' } from '../../config/api/system.js'
// 导入地图工具函数 // 导入地图工具函数
@@ -291,25 +291,110 @@
} }
const noticeText = ref('') const noticeText = ref('')
const getNoticeText = async () => { const bannerImages = ref([]) // 首页广告图片列表
const parasm = {
'title': '用户端公告' // 将语言代码转换为后端接受的格式
const convertLanguageCode = (lang) => {
// zh-CN -> zh_CN (转换下划线)
// en-US -> en_US (转换下划线)
return lang.replace(/-/g, '_')
} }
const res = await getNoticeTextData(parasm);
noticeText.value = res.data.noticeContent; // 获取公告内容(支持多语言)
const getNoticeText = 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/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 (res.data.noticeContent) { if (announcement) {
noticeHeight.value = 50 // 通知栏高度约50px noticeHeight.value = 50 // 通知栏高度约50px
} }
// 将通知内容存储到本地缓存 // 将通知内容存储到本地缓存
try { try {
uni.setStorageSync('noticeContent', res.data.noticeContent); uni.setStorageSync('noticeContent', announcement)
console.log('通知内容已缓存:', res.data.noticeContent); console.log('通知内容已缓存:', announcement)
} catch (e) { } catch (e) {
console.warn('缓存通知内容失败:', 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' })
} }
// 查询最近的活动 // 查询最近的活动
@@ -442,7 +527,12 @@
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
testDistanceCalculation() testDistanceCalculation()
} }
await getNoticeText();
// 并行加载公告和广告(不依赖定位)
await Promise.all([
getNoticeText(),
getBannerImages()
])
// 1. 先获取用户位置 // 1. 先获取用户位置
await getUserLocationAndAddress() await getUserLocationAndAddress()
+134 -27
View File
@@ -1,40 +1,118 @@
<template> <template>
<view class="loading-page"> <!-- 加载状态 -->
<view v-if="loading" class="loading-page">
<view class="loading-content"> <view class="loading-content">
<view class="loading-spinner"></view> <view class="loading-spinner"></view>
<text>{{ $t('common.loading') }}</text> <text>{{ $t('common.loading') }}</text>
</view> </view>
</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> </template>
<script setup> <script setup>
import { onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useI18n } from '@/utils/i18n.js' import { useI18n } from '@/utils/i18n.js'
import { URL } from '@/config/url.js'
const { t: $t } = useI18n() const { t: $t } = useI18n()
onMounted(() => { // 响应式数据
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 currentLang = uni.getStorageSync('language') || 'zh-CN'
const languageCode = convertLanguageCode(currentLang)
// 根据语言跳转到对应页面 console.log('加载用户协议,语言:', currentLang, '转换后:', languageCode)
const targetPage = currentLang === 'en-US'
? '/pages/legal/agreement-en'
: '/pages/legal/agreement-zh'
console.log('当前语言:', currentLang, '跳转到:', targetPage) // 调用接口获取协议内容
const res = await uni.request({
// 使用 redirectTo 替换当前页面 url: `${URL}/device/agreementConfig/current`,
uni.redirectTo({ method: 'GET',
url: targetPage, header: {
fail: (err) => { 'Content-Language': languageCode,
console.error('跳转失败:', err) 'Authorization': 'Bearer ' + uni.getStorageSync('token'),
// 如果跳转失败,默认跳转到中文版 'Clientid': uni.getStorageSync('client_id')
uni.redirectTo({ },
url: '/pages/legal/agreement-zh' 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> </script>
@@ -68,9 +146,40 @@
100% { transform: rotate(360deg); } 100% { transform: rotate(360deg); }
} }
text { .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; font-size: 28rpx;
color: #666; 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 { .legal-page {
@@ -83,33 +192,31 @@
.header { .header {
margin-bottom: 16rpx; margin-bottom: 16rpx;
.title { .title {
font-size: 40rpx; font-size: 40rpx;
font-weight: 600; font-weight: 600;
color: #222; color: #222;
margin-bottom: 8rpx; margin-bottom: 8rpx;
display: block;
} }
.subtitle { .subtitle {
font-size: 24rpx; font-size: 24rpx;
color: #888; color: #888;
display: block;
} }
} }
.content { .content {
// width: 100%;
background: #fff; background: #fff;
border-radius: 16rpx; border-radius: 16rpx;
padding: 16rpx 20rpx; padding: 20rpx;
flex: 1; flex: 1;
min-height: 0;
box-sizing: border-box; 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 { .footer {
text-align: center; text-align: center;
margin-top: 16rpx; margin-top: 16rpx;
+131 -51
View File
@@ -1,40 +1,118 @@
<template> <template>
<view class="loading-page"> <!-- 加载状态 -->
<view v-if="loading" class="loading-page">
<view class="loading-content"> <view class="loading-content">
<view class="loading-spinner"></view> <view class="loading-spinner"></view>
<text>{{ $t('common.loading') }}</text> <text>{{ $t('common.loading') }}</text>
</view> </view>
</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> </template>
<script setup> <script setup>
import { onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useI18n } from '@/utils/i18n.js' import { useI18n } from '@/utils/i18n.js'
import { URL } from '@/config/url.js'
const { t: $t } = useI18n() const { t: $t } = useI18n()
onMounted(() => { // 响应式数据
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 currentLang = uni.getStorageSync('language') || 'zh-CN'
const languageCode = convertLanguageCode(currentLang)
// 根据语言跳转到对应页面 console.log('加载隐私政策,语言:', currentLang, '转换后:', languageCode)
const targetPage = currentLang === 'en-US'
? '/pages/legal/privacy-en'
: '/pages/legal/privacy-zh'
console.log('当前语言:', currentLang, '跳转到:', targetPage) // 调用接口获取协议内容
const res = await uni.request({
// 使用 redirectTo 替换当前页面 url: `${URL}/device/agreementConfig/current`,
uni.redirectTo({ method: 'GET',
url: targetPage, header: {
fail: (err) => { 'Content-Language': languageCode,
console.error('跳转失败:', err) 'Authorization': 'Bearer ' + uni.getStorageSync('token'),
// 如果跳转失败,默认跳转到中文版 'Clientid': uni.getStorageSync('client_id')
uni.redirectTo({ },
url: '/pages/legal/privacy-zh' 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> </script>
@@ -68,9 +146,40 @@
100% { transform: rotate(360deg); } 100% { transform: rotate(360deg); }
} }
text { .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; font-size: 28rpx;
color: #666; 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 { .legal-page {
@@ -83,60 +192,31 @@
.header { .header {
margin-bottom: 16rpx; margin-bottom: 16rpx;
}
.title { .title {
font-size: 40rpx; font-size: 40rpx;
font-weight: 600; font-weight: 600;
color: #222; color: #222;
margin-bottom: 8rpx; margin-bottom: 8rpx;
display: block;
} }
.subtitle { .subtitle {
font-size: 24rpx; font-size: 24rpx;
color: #888; color: #888;
display: block;
} }
.card {
background: #fff;
border-radius: 16rpx;
padding: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}
.notice {
margin-bottom: 16rpx;
} }
.content { .content {
background: #fff; background: #fff;
border-radius: 16rpx; border-radius: 16rpx;
padding: 16rpx 20rpx; padding: 20rpx;
flex: 1; flex: 1;
min-height: 0;
box-sizing: border-box; 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 { .footer {
text-align: center; text-align: center;
margin-top: 16rpx; margin-top: 16rpx;
+73 -1
View File
@@ -24,7 +24,18 @@
</view> --> </view> -->
<view class="section"> <view class="section">
<view class="banner-card" @click="navigateTo('/pages/join/index')"> <!-- 广告轮播 -->
<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> <image class="banner-image" src="/static/userCenter_swiper.png" mode="aspectFill"></image>
</view> </view>
<!-- <view class="section-title">常用服务</view> --> <!-- <view class="section-title">常用服务</view> -->
@@ -147,6 +158,60 @@ import {
const appVersion = ref('1.0.0'); const appVersion = ref('1.0.0');
const showMenuItem = ref(false) 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(() => { onMounted(() => {
@@ -155,11 +220,13 @@ import {
}) })
getInfo(); getInfo();
initVersion(); initVersion();
getBannerImages(); // 加载广告
}); });
// 页面显示时刷新用户信息 // 页面显示时刷新用户信息
onShow(() => { onShow(() => {
getInfo(); getInfo();
getBannerImages(); // 刷新广告
}); });
// 获取用户信息 // 获取用户信息
@@ -571,6 +638,11 @@ import {
border: 1rpx solid #f0f0f0; border: 1rpx solid #f0f0f0;
} }
.banner-swiper {
width: 100%;
height: 260rpx;
}
.banner-image { .banner-image {
width: 100%; width: 100%;
height: 260rpx; height: 260rpx;
+481 -492
View File
File diff suppressed because it is too large Load Diff