mi-assessment/uniapp/pages/mine/index.vue
18631081161 34030cf2ea
All checks were successful
continuous-integration/drone/push Build is passing
界面优化
2026-04-07 19:58:30 +08:00

562 lines
12 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="mine-page">
<!-- 顶部渐变背景层 -->
<!-- <view class="top-gradient"></view> -->
<!-- 导航栏占位 -->
<view class="navbar-placeholder" :style="{ height: totalNavbarHeight + 'px' }"></view>
<!-- 页面内容 -->
<view class="page-content">
<!-- 用户信息区域 -->
<view class="user-section" @click="handleUserClick">
<image
class="user-avatar"
:src="isLoggedIn ? (userInfo.avatar || '/static/mine/icon-user.png') : '/static/mine/icon-user.png'"
mode="aspectFill"
/>
<view class="user-info">
<text class="user-name">{{ isLoggedIn ? (userInfo.nickname || '用户') : '点击登录' }}</text>
<text v-if="isLoggedIn" class="user-uid">UID: {{ userInfo.uid || '--' }}</text>
</view>
<text class="user-arrow"></text>
</view>
<!-- 常用功能 -->
<view class="menu-section">
<text class="section-title">常用功能</text>
<view class="menu-list">
<view class="menu-item" @click="goOrderList">
<image class="menu-icon" src="/static/mine/icon-order.png" mode="aspectFit" />
<text class="menu-label">我的订单</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="goAssessmentHistory">
<image class="menu-icon" src="/static/mine/icon-assessment-history.png" mode="aspectFit" />
<text class="menu-label">往期测评</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="handleContactUs">
<image class="menu-icon" src="/static/mine/icon-contact.png" mode="aspectFit" />
<text class="menu-label">联系我们</text>
<text class="menu-arrow"></text>
</view>
<view v-if="isPartner" class="menu-item" @click="goInvite">
<image class="menu-icon" src="/static/mine/icon-invite.png" mode="aspectFit" />
<text class="menu-label">邀请新用户</text>
<text class="menu-arrow"></text>
</view>
</view>
</view>
<!-- 其他功能 -->
<view class="menu-section">
<text class="section-title">其他功能</text>
<view class="menu-list">
<view class="menu-item" @click="goAbout">
<image class="menu-icon" src="/static/mine/icon-about.png" mode="aspectFit" />
<text class="menu-label">关于</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="goUserAgreement">
<image class="menu-icon" src="/static/mine/icon-user-agreement.png" mode="aspectFit" />
<text class="menu-label">用户协议</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="goPrivacyPolicy">
<image class="menu-icon" src="/static/mine/icon-privacy-policy.png" mode="aspectFit" />
<text class="menu-label">隐私协议</text>
<text class="menu-arrow"></text>
</view>
<view v-if="isLoggedIn" class="menu-item" @click="showLogoutPopup">
<image class="menu-icon" src="/static/mine/icon-logout.png" mode="aspectFit" />
<text class="menu-label">退出登录</text>
<text class="menu-arrow"></text>
</view>
</view>
</view>
<!-- 底部安全区域 -->
<view class="safe-bottom"></view>
</view>
<!-- 退出登录确认弹窗 -->
<view v-if="logoutPopupVisible" class="popup-mask" @click="hideLogoutPopup">
<view class="popup-container" @click.stop>
<view class="popup-content">
<text class="popup-title">提示</text>
<text class="popup-message">确定要退出登录吗?</text>
</view>
<view class="popup-buttons">
<view class="popup-btn cancel" @click="hideLogoutPopup">
<text>取消</text>
</view>
<view class="popup-btn confirm" @click="handleLogout">
<text>确定</text>
</view>
</view>
</view>
</view>
<!-- 联系我们弹窗 -->
<view v-if="contactPopupVisible" class="popup-mask" @click="hideContactPopup">
<view class="contact-popup" @click.stop>
<view class="contact-popup-header">
<text class="contact-popup-title">联系我们</text>
<text class="contact-popup-close" @click="hideContactPopup">✕</text>
</view>
<view class="contact-popup-body">
<image
class="contact-qrcode"
:src="contactQrcodeUrl"
mode="widthFix"
@click="handleSaveQrcode"
/>
</view>
</view>
</view>
</view>
</template>
<script setup>
/**
* 我的页面
* 展示用户信息和功能入口
*/
import { ref, computed, onMounted } from 'vue'
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/user.js'
import { useNavbar } from '@/composables/useNavbar.js'
import { getContactInfo } from '@/api/system.js'
const userStore = useUserStore()
const { totalNavbarHeight } = useNavbar()
// 退出登录弹窗状态
const logoutPopupVisible = ref(false)
// 联系我们弹窗状态
const contactPopupVisible = ref(false)
const contactQrcodeUrl = ref('')
// 计算属性
const isLoggedIn = computed(() => userStore.isLoggedIn)
const isPartner = computed(() => userStore.isPartner)
const userInfo = computed(() => ({
userId: userStore.userId,
uid: userStore.uid,
nickname: userStore.nickname,
avatar: userStore.avatar
}))
/**
* 点击用户区域
*/
function handleUserClick() {
if (isLoggedIn.value) {
goProfile()
} else {
handleLogin()
}
}
/**
* 跳转登录页
*/
function handleLogin() {
uni.navigateTo({
url: '/pages/login/index'
})
}
/**
* 跳转个人资料页
*/
function goProfile() {
uni.navigateTo({
url: '/pages/mine/profile/index'
})
}
/**
* 跳转我的订单
*/
function goOrderList() {
uni.navigateTo({
url: '/pages/order/list/index'
})
}
/**
* 跳转往期测评
*/
function goAssessmentHistory() {
uni.navigateTo({
url: '/pages/assessment/history/index'
})
}
/**
* 联系我们 - 弹出客服二维码弹窗
*/
async function handleContactUs() {
try {
const res = await getContactInfo()
if (res && res.code === 0 && res.data && res.data.qrcodeUrl) {
contactQrcodeUrl.value = res.data.qrcodeUrl
contactPopupVisible.value = true
} else {
uni.showToast({ title: '暂未配置客服信息', icon: 'none' })
}
} catch (error) {
console.error('获取联系信息失败:', error)
uni.showToast({ title: '获取联系信息失败', icon: 'none' })
}
}
/**
* 关闭联系我们弹窗
*/
function hideContactPopup() {
contactPopupVisible.value = false
}
/**
* 长按保存二维码图片
*/
function handleSaveQrcode() {
if (!contactQrcodeUrl.value) return
uni.previewImage({
urls: [contactQrcodeUrl.value],
current: contactQrcodeUrl.value
})
}
/**
* 跳转邀请新用户
*/
function goInvite() {
uni.navigateTo({
url: '/pages/invite/index'
})
}
/**
* 跳转关于页
*/
function goAbout() {
uni.navigateTo({
url: '/pages/about/index'
})
}
/**
* 跳转用户协议
*/
function goUserAgreement() {
uni.navigateTo({
url: '/pages/agreement/user/index'
})
}
/**
* 跳转隐私协议
*/
function goPrivacyPolicy() {
uni.navigateTo({
url: '/pages/agreement/privacy/index'
})
}
/**
* 显示退出登录弹窗
*/
function showLogoutPopup() {
logoutPopupVisible.value = true
}
/**
* 隐藏退出登录弹窗
*/
function hideLogoutPopup() {
logoutPopupVisible.value = false
}
/**
* 处理退出登录
*/
function handleLogout() {
userStore.logout()
logoutPopupVisible.value = false
uni.showToast({
title: '已退出登录',
icon: 'success'
})
}
/**
* 页面显示时刷新用户信息
*/
onShow(() => {
if (userStore.isLoggedIn) {
userStore.fetchUserInfo()
}
})
/**
* 下拉刷新
*/
onPullDownRefresh(async () => {
if (userStore.isLoggedIn) {
await userStore.fetchUserInfo()
}
uni.stopPullDownRefresh()
})
/**
* 页面加载
*/
onMounted(() => {
userStore.restoreFromStorage()
})
</script>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.mine-page {
min-height: 100vh;
background-color: #F3F3F3;
position: relative;
}
// 顶部渐变背景
.top-gradient {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 500rpx;
background: linear-gradient(177deg, #FFEFDE 1%, #F3F3F3 28%);
z-index: 0;
}
.navbar-placeholder {
width: 100%;
position: relative;
z-index: 1;
}
// 页面内容
.page-content {
padding: $spacing-lg;
padding-bottom: env(safe-area-inset-bottom);
position: relative;
z-index: 1;
}
// 用户信息区域
.user-section {
display: flex;
align-items: center;
padding: $spacing-xl 0;
margin-bottom: $spacing-lg;
.user-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
margin-right: $spacing-lg;
}
.user-info {
flex: 1;
display: flex;
flex-direction: column;
.user-name {
font-size: $font-size-xl;
font-weight: $font-weight-medium;
color: $text-color;
}
.user-uid {
font-size: $font-size-sm;
color: $text-placeholder;
margin-top: 8rpx;
}
}
.user-arrow {
font-size: 40rpx;
color: $text-placeholder;
}
}
// 菜单区域
.menu-section {
margin-bottom: $spacing-xl;
.section-title {
display: block;
font-size: $font-size-lg;
font-weight: $font-weight-bold;
color: $text-color;
margin-bottom: $spacing-md;
}
.menu-list {
background-color: transparent;
}
}
// 菜单项
.menu-item {
display: flex;
align-items: center;
padding: $spacing-lg 0;
&:active {
opacity: 0.7;
}
.menu-icon {
width: 44rpx;
height: 44rpx;
margin-right: $spacing-lg;
}
.menu-label {
flex: 1;
font-size: $font-size-md;
color: $text-color;
}
.menu-arrow {
font-size: 32rpx;
color: $text-placeholder;
}
}
// 底部安全区域
.safe-bottom {
height: 40rpx;
padding-bottom: env(safe-area-inset-bottom);
}
// 退出登录弹窗
.popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: $bg-mask;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.popup-container {
width: 560rpx;
background-color: $bg-white;
border-radius: $border-radius-lg;
overflow: hidden;
.popup-content {
padding: 60rpx 40rpx 40rpx;
text-align: center;
.popup-title {
display: block;
font-size: $font-size-lg;
font-weight: $font-weight-medium;
color: $text-color;
margin-bottom: $spacing-md;
}
.popup-message {
display: block;
font-size: $font-size-md;
color: $text-secondary;
}
}
.popup-buttons {
display: flex;
border-top: 1rpx solid $border-light;
.popup-btn {
flex: 1;
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
&:active {
background-color: $bg-gray;
}
text {
font-size: $font-size-lg;
}
&.cancel {
border-right: 1rpx solid $border-light;
text {
color: $text-secondary;
}
}
&.confirm {
text {
color: $primary-color;
}
}
}
}
}
// 联系我们弹窗
.contact-popup {
width: 90%;
background-color: $bg-white;
border-radius: $border-radius-xl;
overflow: hidden;
.contact-popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-xl $spacing-xl 0;
.contact-popup-title {
font-size: $font-size-lg;
font-weight: $font-weight-bold;
color: $text-color;
}
.contact-popup-close {
font-size: $font-size-xl;
color: $text-placeholder;
padding: $spacing-xs;
}
}
.contact-popup-body {
display: flex;
flex-direction: column;
align-items: center;
padding: $spacing-xl;
.contact-qrcode {
width: 100%;
border-radius: $border-radius-md;
}
}
}
</style>