style:根据UI设计图跳转页面样式

This commit is contained in:
2025-10-15 01:35:23 +08:00
parent 4408673438
commit 46179c5d3f
30 changed files with 4632 additions and 2459 deletions
+405 -291
View File
@@ -1,124 +1,109 @@
<template>
<view class="profile-container">
<!-- 用户信息区域 -->
<view class="header-section">
<view class="user-profile" @click="handleUserProfileClick">
<view class="avatar-container">
<image class="avatar" v-if="userInfo.avatar" :src="userInfo.avatar" mode="aspectFill">
</image>
<image v-else class="avatar" src="@/static/user-active.png" mode="aspectFill"></image>
<view class="avatar-badge" v-if="userInfo.isAdmin"></view>
</view>
<view class="user-details" v-if="userInfo">
<view class="username">{{ userInfo.nickName }}</view>
<view class="user-id">{{ userInfo.phone ? maskPhone(userInfo.phone) : '未绑定手机号' }}</view>
</view>
<view class="user-details" v-else>
<view class="username">点击登录</view>
<view class="user-id">授权登录后享受更多服务</view>
</view>
<view class="edit-profile">
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
<view class="my-page">
<view class="user-card">
<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>
<!-- 覆盖在头像上的微信选择头像授权按钮仅小程序生效 -->
<!-- #ifdef MP-WEIXIN -->
<button class="avatar-choose-btn" open-type="chooseAvatar" @chooseavatar="onChooseAvatar"></button>
<!-- #endif -->
</view>
<view class="user-text">
<view class="nickname">{{ userInfo.nickName || '点击登录' }}</view>
<view class="subtext">{{ userInfo.phone ? maskPhone(userInfo.phone) : '授权登录后可查看订单与资产' }}</view>
</view>
<uv-icon type="right" size="16" color="#999"></uv-icon>
</view>
<!-- 余额卡片 -->
<view class="balance-card">
<view class="balance-info">
<view class="balance-label">押金余额</view>
<view class="balance-amount">¥{{ deposit }}</view>
<!-- <view class="assets-card">
<view class="assets-left">
<view class="label">押金余额</view>
<view class="amount">¥{{ deposit }}</view>
</view>
<view class="action-button" @click="handleWithdraw">
<text>提现</text>
</view>
</view>
<!-- 功能区域列表 -->
<view class="function-list">
<!-- 订单中心 -->
<view class="function-item" @click="navigateTo('/pages/order/index')">
<view class="item-left">
<view class="item-icon">
<image src="/static/jl.png" mode="aspectFit"></image>
</view>
<text class="item-title">订单中心</text>
</view>
<view class="item-right">
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 投诉建议 -->
<view class="function-item" @click="navigateTo('/pages/feedback/index')">
<view class="item-left">
<view class="item-icon">
<image src="/static/complaint.png" mode="aspectFit"></image>
</view>
<text class="item-title">投诉建议</text>
</view>
<view class="item-right">
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 帮助中心 -->
<view class="function-item" @click="navigateTo('/pages/help/index')">
<view class="item-left">
<view class="item-icon">
<image src="/static/hlep.png" mode="aspectFit"></image>
</view>
<text class="item-title">帮助中心</text>
</view>
<view class="item-right">
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<view class="function-item" @click="navigateTo('/pages/expressReturn/index')">
<view class="item-left">
<view class="item-icon">
<image src="/static/express.png" mode="aspectFit"></image>
</view>
<text class="item-title">快递归还</text>
</view>
<view class="item-right">
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<view class="function-item" @click="doLogout()">
<view class="item-left">
<view class="item-icon">
<image src="/static/logout.png" mode="aspectFit"></image>
</view>
<text class="item-title">退出登录</text>
</view>
<view class="item-right">
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
</view>
<!--
<view class="section-title">设置</view>
<view class="settings-list">
<view
v-for="(item, index) in settingItems"
:key="index"
class="settings-item"
@click="item.action">
<view class="settings-item-left">
<uni-icons :type="item.icon" size="20" color="#4facfe"></uni-icons>
<text>{{ item.name }}</text>
</view>
<uni-icons type="right" size="16" color="#999"></uni-icons>
<view class="assets-right" @click="handleWithdraw">
<text class="withdraw-btn">提现</text>
</view>
</view> -->
<!-- <u-popup ref="authPopup" mode="center" border-radius="15" width="600rpx" @open="onPopupOpen" @close="onPopupClose">
<view class="section">
<view class="banner-card">
<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">快速归还</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<view class="list-item" @click="navigateTo('/pages/expressReturn/index')">
<view class="left">
<image class="icon" src="/static/express.png" mode="aspectFit"></image>
<text class="title">快递归还记录</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">我的订单</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">客服中心</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/complaint.png" mode="aspectFit"></image>
<text class="title">投诉与建议</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/peopleInWork.png" mode="aspectFit"></image>
<text class="title">营业资质</text>
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<view class="list-item" @click="navigateTo('/pages/serve/bagCheck/index')">
<view class="left">
<image class="icon" src="/static/other_device.png" mode="aspectFit"></image>
<text class="title">合作加盟</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">设置</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')">服务条款</text>
<text class="sep"></text>
<text class="link" @click="navigateTo('/pages/legal/privacy')">隐私政策</text>
</view>
<view class="version">v{{ 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>
@@ -127,7 +112,8 @@
<button class="confirm-btn" @click="getUserProfile">确定</button>
</view>
</view>
</u-popup> -->
</u-popup>
-->
</view>
</template>
@@ -142,9 +128,9 @@
wxLogin,
getUserInfo
} from '../../util/index.js';
import {
userLogout
} from '@/config/user.js'
import { uploadUserAvatar } from '../../config/user.js'
import { URL } from '../../config/url.js'
// 设置页执行退出登录,此页不再直接调用
// 响应式状态
const userInfo = ref({});
@@ -152,10 +138,12 @@
const openId = ref('');
const authPopup = ref(null); // u-popup 的引用
const isPopupVisible = ref(false);
const appVersion = ref('1.0.0');
// 页面加载时初始化
onMounted(() => {
getInfo();
initVersion();
});
// 获取用户信息
@@ -194,6 +182,26 @@
}
};
// 初始化应用版本号(多端兼容,取可用信息)
const initVersion = () => {
// #ifdef MP-WEIXIN
try {
const info = wx.getAccountInfoSync && wx.getAccountInfoSync();
if (info && info.miniProgram && info.miniProgram.version) {
appVersion.value = info.miniProgram.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()
@@ -219,6 +227,52 @@
});
};
// 处理快速归还
const handleQuickReturn = async () => {
try {
uni.showLoading({
title: '加载中'
});
// 获取使用中的订单
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: '暂无使用中的订单',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('获取使用中订单失败:', error);
uni.showToast({
title: '获取订单失败',
icon: 'none'
});
}
};
// 处理提现按钮点击
const handleWithdraw = () => {
navigateTo('/pages/deposit/index');
@@ -226,15 +280,49 @@
// 处理用户资料点击
const handleUserProfileClick = () => {
if (!userInfo.value) {
// 打开授权弹窗
openAuthPopup();
} else {
// 已登录用户点击个人资料,可以导航到编辑页面
// navigateTo('/pages/profile/edit');
const token = uni.getStorageSync('token')
if (!token) {
redirectToLogin()
return
}
// #ifdef MP-WEIXIN
getUserProfile()
// #endif
// #ifndef MP-WEIXIN
uni.showToast({ title: '请在微信小程序中使用此功能', 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: '上传中...', 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) {
@@ -270,6 +358,7 @@
success: (res) => {
console.log('获取用户信息成功:', res);
updateUserInfo(res.userInfo);
uploadAvatarAndRefresh(res.userInfo);
},
fail: (err) => {
console.error('获取用户信息失败:', err);
@@ -331,6 +420,46 @@
}
};
// 下载并上传头像,更新用户信息
const uploadAvatarAndRefresh = async (wxUserInfo) => {
try {
const avatarUrl = wxUserInfo?.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) {
@@ -362,222 +491,221 @@
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
const doLogout = async () => {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: async (res) => {
if (res.confirm) {
const response = await userLogout();
if (response.code == 200) {
uni.showToast({
title:'退出成功',
icon:'none'
})
setTimeout(() => {
uni.removeStorageSync('token');
uni.removeStorageSync('userInfo');
uni.redirectTo({
url: '/pages/login/index'
})
}, 1500)
}
}
}
})
}
// 退出登录移动至设置页
</script>
<style lang="scss" scoped>
.profile-container {
.my-page {
min-height: 100vh;
background-color: #f5f7fa;
background-color: #ffffff;
position: -webkit-sticky;
position: sticky;
top: 0;
padding-bottom: env(safe-area-inset-bottom);
display: flex;
flex-direction: column;
}
/* Header Section */
.header-section {
padding: 40rpx;
background: linear-gradient(135deg, #07c160, #05a14e);
position: relative;
border-radius: 0 0 30rpx 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 10rpx 30rpx rgba(7, 193, 96, 0.25);
}
.user-profile {
.user-card {
display: flex;
align-items: center;
padding: 20rpx 0;
padding: 24rpx 30rpx;
// background-color: #D1FFE1;
background: linear-gradient(180deg, #D1FFE1 0%, #ffffff 100%);
// border-bottom: 1rpx solid #f0f0f0;
// margin: 0 20rpx;
}
.avatar-container {
.banner-card {
margin: 20rpx 30rpx 0 30rpx;
background-color: #ffffff;
border-radius: 50rpx;
overflow: hidden;
border: 1rpx solid #f0f0f0;
}
.banner-image {
width: 100%;
height: 260rpx;
border-radius: 50rpx;
display: block;
}
.avatar-box {
margin-right: 20rpx;
position: relative;
margin-right: 30rpx;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
border: 4rpx solid rgba(255, 255, 255, 0.6);
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.1);
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
background-color: #f0f0f0;
}
.avatar-badge {
/* 仅小程序端存在,此按钮覆盖在头像上捕获点击以触发选择头像 */
/* #ifdef MP-WEIXIN */
.avatar-choose-btn {
position: absolute;
bottom: 0;
right: 0;
width: 36rpx;
height: 36rpx;
border-radius: 18rpx;
background-color: #ff9500;
border: 4rpx solid white;
left: 0;
top: 0;
width: 100rpx;
height: 100rpx;
border: none;
background: transparent;
padding: 0;
margin: 0;
opacity: 0; /* 保持可点击但不可见 */
}
/* #endif */
.user-details {
.user-text {
flex: 1;
}
.username {
font-size: 36rpx;
.nickname {
font-size: 32rpx;
color: #222222;
font-weight: 600;
color: white;
margin-bottom: 8rpx;
}
.user-id {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
.subtext {
margin-top: 6rpx;
font-size: 24rpx;
color: #999999;
}
.edit-profile {
background-color: rgba(255, 255, 255, 0.2);
padding: 10rpx;
border-radius: 50%;
}
/* Balance Card */
.balance-card {
margin: 30rpx;
background: white;
border-radius: 20rpx;
padding: 30rpx;
.assets-card {
margin: 20rpx 0;
padding: 24rpx 30rpx;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
align-items: center;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.05);
}
.balance-label {
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
}
.balance-amount {
font-size: 48rpx;
font-weight: 600;
color: #07c160;
}
.action-button {
background: linear-gradient(135deg, #07c160, #05a14e);
border-radius: 40rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 0 40rpx;
color: white;
font-weight: 500;
font-size: 30rpx;
box-shadow: 0 8rpx 16rpx rgba(7, 193, 96, 0.25);
&:active {
opacity: 0.9;
transform: scale(0.98);
}
text {
margin-right: 10rpx;
}
}
/* Function List */
.function-list {
margin: 30rpx;
background: white;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
}
.function-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 30rpx;
border-top: 1rpx solid #f0f0f0;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
&:active {
background-color: #f9f9f9;
}
}
.item-left {
.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;
}
.item-icon {
width: 48rpx;
height: 48rpx;
margin-right: 24rpx;
.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;
image {
width: 40rpx;
height: 40rpx;
.link-box{
display: flex;
align-items: center;
justify-content: center;
}
}
.item-title {
font-size: 30rpx;
color: #333;
font-weight: 500;
.footer-agreements .link {
color: #999999;
}
.item-right {
display: flex;
align-items: center;
.footer-agreements .sep {
margin: 0 10rpx;
color: #c0c0c0;
}
/* Auth Popup */
.footer-agreements .version {
margin-top: 10rpx;
color: #c0c0c0;
font-size: 20rpx;
}
/* 保留弹窗样式(未启用) */
.auth-popup {
background-color: white;
background-color: #ffffff;
width: 100%;
padding: 40rpx;
border-radius: 15rpx;
border-radius: 12rpx;
}
.auth-title {
font-size: 34rpx;
font-weight: 600;
color: #333;
color: #333333;
text-align: center;
margin-bottom: 20rpx;
}
.auth-desc {
font-size: 28rpx;
color: #666;
color: #666666;
text-align: center;
margin-bottom: 40rpx;
}
@@ -595,19 +723,5 @@
text-align: center;
border-radius: 40rpx;
font-size: 28rpx;
&::after {
border: none;
}
}
.cancel-btn {
background-color: #f0f0f0;
color: #666;
}
.confirm-btn {
background: linear-gradient(135deg, #07c160, #05a14e);
color: white;
}
</style>