Files
uni-fans-score/pages/my/index.vue
T

819 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="my-page">
<view class="user-card" @click="navigateTo('/pages/userProfile/index')">
<view class="avatar-box">
<image class="avatar" v-if="userInfo.avatar" :src="userInfo.avatar" mode="aspectFill"></image>
<image v-else class="avatar" src="@/static/head.png" mode="aspectFill"></image>
</view>
<view class="user-text">
<view class="nickname">{{ userInfo.nickName || $t('user.clickToLogin') }}</view>
<view class="subtext">{{ userInfo.phone ? maskPhone(userInfo.phone) : $t('user.loginPrompt') }}</view>
</view>
<uv-icon name="arrow-right" size="16" color="#999"></uv-icon>
</view>
<!-- <view class="assets-card">
<view class="assets-left">
<view class="label">押金余额</view>
<view class="amount">¥{{ deposit }}</view>
</view>
<view class="assets-right" @click="handleWithdraw">
<text class="withdraw-btn">提现</text>
</view>
</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">
<view class="left">
<image class="icon" src="/static/express_return.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.quickReturn') }}<text style="font-size: 18rpx;">{{ $t('user.quickReturnDesc') }}</text></text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<view class="list-item" @click="navigateTo('/pages/expressReturn/index')" v-if="showMenuItem">
<view class="left">
<image class="icon" src="/static/express.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.expressReturn') }}</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<view class="list-item" @click="navigateTo('/pages/order/index')">
<view class="left">
<image class="icon" src="/static/orderList.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.myOrders') }}</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<view class="list-item" @click="navigateTo('/pages/help/index')">
<view class="left">
<image class="icon" src="/static/customer-service.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.customerService') }}</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<view class="list-item" @click="navigateTo('/pages/feedback/index')">
<view class="left">
<image class="icon" src="/static/suggess.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.feedback') }}</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<!-- <view class="list-item" @click="navigateTo('/pages/legal/agreement')">
<view class="left">
<image class="icon" src="/static/business-licence.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.businessLicense') }}</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view> -->
<view class="list-item" @click="navigateTo('/pages/join/index')">
<view class="left">
<image class="icon" src="/static/peopleInWork.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.cooperation') }}</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<view class="list-item" @click="navigateTo('/pages/setting/index')">
<view class="left">
<image class="icon" src="/static/setting.png" mode="aspectFit"></image>
<text class="title">{{ $t('user.settings') }}</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
</view>
</view>
<view class="footer-agreements">
<view class="link-box">
<text class="link" @click="navigateTo('/pages/legal/agreement')">{{ $t('user.userAgreement') }}</text>
<text class="sep"></text>
<text class="link" @click="navigateTo('/pages/legal/privacy')">{{ $t('user.privacyPolicy') }}</text>
</view>
<view class="version">{{ $t('user.version') }}{{ appVersion }}</view>
</view>
<!-- 保留授权弹窗,暂不启用 -->
<!--
<u-popup ref="authPopup" mode="center" border-radius="15" width="600rpx" @open="onPopupOpen" @close="onPopupClose">
<view class="auth-popup">
<view class="auth-title">授权登录</view>
<view class="auth-desc">获取您的支付宝头像、昵称等公开信息</view>
<view class="auth-buttons">
<button class="cancel-btn" @click="closeAuthPopup">取消</button>
<button class="confirm-btn" @click="getUserProfile">确定</button>
</view>
</view>
</u-popup>
-->
</view>
</template>
<script setup>
import {
ref,
reactive,
onMounted
} from 'vue';
import {
onShow
} from '@dcloudio/uni-app';
import {
alipayLogin,
getUserInfo
} from '../../util/index.js';
import {
uploadUserAvatar
} from '../../config/api/user.js'
import {
URL
} from '../../config/url.js'
import { useI18n } from '@/utils/i18n.js'
// 设置页执行退出登录,此页不再直接调用
const { t: $t } = useI18n()
// 响应式状态
const userInfo = ref({});
const deposit = ref('0.00');
const openId = ref('');
const authPopup = ref(null); // u-popup 的引用
const isPopupVisible = ref(false);
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: 'alipay', // 支付宝平台
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(() => {
uni.setNavigationBarTitle({
title: $t('user.personalCenter')
})
getInfo();
initVersion();
getBannerImages(); // 加载广告
});
// 页面显示时刷新用户信息
onShow(() => {
getInfo();
getBannerImages(); // 刷新广告
});
// 获取用户信息
const getInfo = async () => {
try {
const res = await getUserInfo();
console.log('User info response:', res);
if (res.code == 401 || res.code == 40101) {
redirectToLogin()
return
} else if (res.code == 200) {
// 保存openId
if (res.data.openId) {
openId.value = res.data.openId;
uni.setStorageSync('openId', res.data.openId);
}
// 更新用户信息
userInfo.value = {
nickName: res.data.nickname,
phone: res.data.phone,
avatar: res.data.iconUrl,
isAdmin: res.data.isAdmin
};
uni.setStorageSync('userInfo', userInfo.value);
deposit.value = res.data.balanceAmount || '0.00';
}
} catch (error) {
console.error('获取用户信息失败:', error);
uni.showToast({
title: $t('user.getUserInfoFailed'),
icon: 'none'
});
}
};
// 初始化应用版本号(多端兼容,取可用信息)
const initVersion = () => {
// #ifdef MP-ALIPAY
try {
// 支付宝小程序获取版本号
const systemInfo = uni.getSystemInfoSync();
if (systemInfo && systemInfo.version) {
appVersion.value = systemInfo.version;
}
} catch (e) {}
// #endif
// #ifdef APP-PLUS
try {
if (typeof plus !== 'undefined' && plus.runtime && plus.runtime.version) {
appVersion.value = plus.runtime.version;
}
} catch (e) {}
// #endif
};
const redirectToLogin = () => {
try {
const pages = getCurrentPages()
const current = pages && pages.length ? pages[pages.length - 1] : null
const route = current && current.route ? ('/' + current.route) : '/pages/index/index'
const query = current && current.options ? Object.keys(current.options).map(k =>
`${k}=${encodeURIComponent(current.options[k])}`).join('&') : ''
const redirect = encodeURIComponent(query ? `${route}?${query}` : route)
uni.reLaunch({
url: `/pages/login/index?redirect=${redirect}`
})
} catch (e) {
uni.reLaunch({
url: '/pages/login/index'
})
}
}
// 导航到指定页面
const navigateTo = (url) => {
uni.navigateTo({
url
});
};
// 处理快速归还
const handleQuickReturn = async () => {
try {
uni.showLoading({
title: $t('common.loading')
});
// 获取使用中的订单
const res = await uni.request({
url: `${URL}/app/order/inUse`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
});
uni.hideLoading();
if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
redirectToLogin();
return;
}
if (res.statusCode === 200 && res.data.code === 200 && res.data.data) {
const inUseOrder = res.data.data;
// 跳转到统一订单详情页面
uni.navigateTo({
url: `/pages/order/detail?orderId=${inUseOrder.orderId}&deviceId=${inUseOrder.deviceNo}`
});
} else {
uni.showToast({
title: $t('order.noOrder'),
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('获取使用中订单失败:', error);
uni.showToast({
title: $t('order.getOrderFailed'),
icon: 'none'
});
}
};
// 处理提现按钮点击
const handleWithdraw = () => {
navigateTo('/pages/deposit/index');
};
// 处理用户资料点击
const handleUserProfileClick = () => {
const token = uni.getStorageSync('token')
if (!token) {
redirectToLogin()
return
}
// #ifdef MP-ALIPAY
// 支付宝小程序通过页面跳转处理用户资料
navigateTo('/pages/userProfile/index')
// #endif
// #ifndef MP-ALIPAY
uni.showToast({
title: $t('auth.pleaseUseInAlipay'),
icon: 'none'
})
// #endif
};
// 小程序原生选择头像回调(需基础库>=2.21.2
const onChooseAvatar = async (e) => {
try {
const token = uni.getStorageSync('token')
if (!token) {
redirectToLogin()
return
}
const avatarLocalPath = e?.detail?.avatarUrl
if (!avatarLocalPath) {
uni.showToast({
title: '未选择头像',
icon: 'none'
})
return
}
uni.showLoading({
title: $t('common.uploading'),
mask: true
})
const uploadRes = await uploadUserAvatar(avatarLocalPath)
const serverAvatar = uploadRes?.data?.url || uploadRes?.url || uploadRes?.data || ''
if (serverAvatar) {
userInfo.value = {
...userInfo.value,
avatar: serverAvatar
}
uni.setStorageSync('userInfo', userInfo.value)
}
uni.showToast({
title: '头像已更新',
icon: 'success'
})
await getInfo()
} catch (err) {
console.error('选择/上传头像失败:', err)
uni.showToast({
title: '头像更新失败',
icon: 'none'
})
} finally {
uni.hideLoading()
}
}
// 打开授权弹窗
const openAuthPopup = () => {
if (authPopup.value) {
authPopup.value.open();
isPopupVisible.value = true;
}
};
// 弹窗打开事件处理
const onPopupOpen = () => {
console.log('授权弹窗已打开');
isPopupVisible.value = true;
// 这里可以添加弹窗打开后的逻辑
};
// 弹窗关闭事件处理
const onPopupClose = () => {
console.log('授权弹窗已关闭');
isPopupVisible.value = false;
// 这里可以添加弹窗关闭后的逻辑
};
// 获取支付宝用户个人信息(已废弃,使用页面跳转方式)
const getUserProfile = () => {
// #ifdef MP-ALIPAY
// 支付宝小程序通过页面跳转处理用户资料
navigateTo('/pages/userProfile/index')
// #endif
// #ifndef MP-ALIPAY
uni.showToast({
title: $t('auth.pleaseUseInAlipay'),
icon: 'none'
});
closeAuthPopup();
// #endif
};
// 更新用户信息(支付宝小程序通过页面跳转处理)
const updateUserInfo = async (alipayUserInfo) => {
try {
// 更新本地用户信息
const updatedInfo = {
...userInfo.value,
nickName: alipayUserInfo.nickName,
avatar: alipayUserInfo.avatarUrl
};
userInfo.value = updatedInfo;
uni.setStorageSync('userInfo', updatedInfo);
uni.showToast({
title: $t('user.updateSuccess'),
icon: 'success'
});
// 更新完成后重新获取用户信息
getInfo();
} catch (error) {
console.error('更新用户信息失败:', error);
uni.showToast({
title: $t('user.updateFailed'),
icon: 'none'
});
}
};
// 下载并上传头像,更新用户信息
const uploadAvatarAndRefresh = async (alipayUserInfo) => {
try {
const avatarUrl = alipayUserInfo?.avatarUrl
if (!avatarUrl) {
uni.showToast({
title: '未获取到头像地址',
icon: 'none'
})
return
}
// 下载支付宝头像为本地临时文件
const tempFilePath = await new Promise((resolve, reject) => {
uni.downloadFile({
url: avatarUrl,
success: (res) => {
if (res.statusCode === 200 && res.tempFilePath) {
resolve(res.tempFilePath)
return
}
reject(new Error('头像下载失败'))
},
fail: reject
})
})
// 上传到后端
const uploadRes = await uploadUserAvatar(tempFilePath)
// 直接使用返回的头像地址(如果有),并刷新用户信息
const serverAvatar = uploadRes?.data?.url || uploadRes?.url || uploadRes?.data || ''
if (serverAvatar) {
userInfo.value = {
...userInfo.value,
avatar: serverAvatar
}
uni.setStorageSync('userInfo', userInfo.value)
}
uni.showToast({
title: '头像已更新',
icon: 'success'
})
await getInfo()
} catch (error) {
console.error('头像上传失败:', error)
uni.showToast({
title: '头像上传失败',
icon: 'none'
})
} finally {
uni.hideLoading()
}
}
// 关闭授权弹窗
const closeAuthPopup = () => {
if (authPopup.value) {
authPopup.value.close();
isPopupVisible.value = false;
}
};
// 关于我们
const handleAboutUs = () => {
uni.showToast({
title: $t('help.functionDeveloping'),
icon: 'none'
});
};
// 隐私政策
const handlePrivacyPolicy = () => {
uni.showToast({
title: $t('help.functionDeveloping'),
icon: 'none'
});
};
// 手机号掩码函数
function maskPhone(phone) {
if (!phone) return '';
// 只处理11位手机号
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
// 退出登录移动至设置页
</script>
<style lang="scss" scoped>
.my-page {
min-height: 100vh;
background-color: #ffffff;
position: -webkit-sticky;
position: sticky;
top: 0;
padding-bottom: env(safe-area-inset-bottom);
display: flex;
flex-direction: column;
}
.user-card {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
// background-color: #D1FFE1;
background: linear-gradient(180deg, #D1FFE1 0%, #ffffff 100%);
// border-bottom: 1rpx solid #f0f0f0;
// margin: 0 20rpx;
}
.banner-card {
margin: 20rpx 30rpx 0 30rpx;
background-color: #ffffff;
border-radius: 50rpx;
overflow: hidden;
border: 1rpx solid #f0f0f0;
}
.banner-swiper {
width: 100%;
height: 260rpx;
}
.banner-image {
width: 100%;
height: 260rpx;
border-radius: 50rpx;
display: block;
}
.avatar-box {
margin-right: 20rpx;
position: relative;
}
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
background-color: #f0f0f0;
}
/* 仅小程序端存在,此按钮覆盖在头像上捕获点击以触发选择头像 */
/* #ifdef MP-WEIXIN */
.avatar-choose-btn {
position: absolute;
left: 0;
top: 0;
width: 100rpx;
height: 100rpx;
border: none;
background: transparent;
padding: 0;
margin: 0;
opacity: 0;
/* 保持可点击但不可见 */
}
/* #endif */
.user-text {
flex: 1;
}
.nickname {
font-size: 32rpx;
color: #222222;
font-weight: 600;
}
.subtext {
margin-top: 6rpx;
font-size: 24rpx;
color: #999999;
}
.assets-card {
margin: 20rpx 0;
padding: 24rpx 30rpx;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid #f0f0f0;
border-bottom: 1rpx solid #f0f0f0;
}
.assets-left .label {
font-size: 26rpx;
color: #666666;
}
.assets-left .amount {
margin-top: 8rpx;
font-size: 40rpx;
color: #e2231a;
font-weight: 600;
}
.withdraw-btn {
display: inline-block;
padding: 14rpx 28rpx;
color: #e2231a;
border: 1rpx solid #e2231a;
border-radius: 6rpx;
font-size: 26rpx;
}
.section {
margin-top: 20rpx;
margin: 0 20rpx 20rpx 20rpx;
background-color: #ffffff;
flex: 1;
// border-top: 1rpx solid #f0f0f0;
// border-bottom: 1rpx solid #f0f0f0;
border-radius: 20rpx;
}
.section-title {
padding: 20rpx 30rpx;
font-size: 26rpx;
color: #999999;
}
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28rpx 30rpx;
border-top: 1rpx solid #f5f5f5;
}
.list-item:first-child {
border-top: none;
}
.left {
display: flex;
align-items: center;
}
.icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.title {
font-size: 30rpx;
color: #333333;
}
.footer-agreements {
margin: 40rpx 0 20rpx 0;
position: absolute;
bottom: 10rpx;
left: 0;
right: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #999999;
font-size: 22rpx;
.link-box {
display: flex;
align-items: center;
justify-content: center;
}
}
.footer-agreements .link {
color: #999999;
}
.footer-agreements .sep {
margin: 0 10rpx;
color: #c0c0c0;
}
.footer-agreements .version {
margin-top: 10rpx;
color: #c0c0c0;
font-size: 20rpx;
}
/* 保留弹窗样式(未启用) */
.auth-popup {
background-color: #ffffff;
width: 100%;
padding: 40rpx;
border-radius: 12rpx;
}
.auth-title {
font-size: 34rpx;
font-weight: 600;
color: #333333;
text-align: center;
margin-bottom: 20rpx;
}
.auth-desc {
font-size: 28rpx;
color: #666666;
text-align: center;
margin-bottom: 40rpx;
}
.auth-buttons {
display: flex;
justify-content: space-between;
}
.cancel-btn,
.confirm-btn {
width: 240rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border-radius: 40rpx;
font-size: 28rpx;
}
</style>