mi-assessment/uniapp/pages/mine/index.vue
zpc 4387b15de0 feat(mine): 完成我的页面改造
- 实现未登录/已登录两种状态样式
- 添加常用功能入口:我的订单、往期测评、联系我们、邀请新用户
- 添加其他功能入口:关于、用户协议、隐私政策、退出登录
- 实现退出登录二次确认弹窗
- 修复 uni.scss 中 SCSS 导入路径问题
- 整理 .gitignore 文件,移除 unpackage 构建目录
2026-02-10 00:12:01 +08:00

607 lines
13 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="custom-navbar" :style="navbarStyle">
<view class="navbar-content" :style="{ height: navbarHeight + 'px' }">
<text class="navbar-title">我的</text>
</view>
</view>
<!-- 导航栏占位 -->
<view class="navbar-placeholder" :style="{ height: totalNavbarHeight + 'px' }"></view>
<!-- 页面内容 -->
<view class="page-content">
<!-- 用户信息区域 -->
<view class="user-section">
<!-- 未登录状态 -->
<view v-if="!isLoggedIn" class="user-card not-logged">
<view class="avatar-wrapper">
<image class="avatar" src="/static/logo.png" mode="aspectFill" />
</view>
<view class="user-info">
<text class="login-tip">登录后体验更多功能</text>
<button class="btn-login" @click="handleLogin">立即登录</button>
</view>
</view>
<!-- 已登录状态 -->
<view v-else class="user-card logged" @click="goProfile">
<view class="avatar-wrapper">
<image
class="avatar"
:src="userInfo.avatar || '/static/logo.png'"
mode="aspectFill"
/>
</view>
<view class="user-info">
<text class="nickname">{{ userInfo.nickname || '用户' }}</text>
<text class="uid">UID: {{ userInfo.uid || '--' }}</text>
</view>
<view class="arrow-icon">
<text class="iconfont"></text>
</view>
</view>
</view>
<!-- 常用功能区域 -->
<view class="menu-section" v-if="isLoggedIn">
<view class="section-title">常用功能</view>
<view class="menu-grid">
<view class="menu-grid-item" @click="goOrderList">
<view class="menu-icon-wrapper order">
<text class="menu-icon-text">📋</text>
</view>
<text class="menu-text">我的订单</text>
</view>
<view class="menu-grid-item" @click="goAssessmentHistory">
<view class="menu-icon-wrapper history">
<text class="menu-icon-text">📊</text>
</view>
<text class="menu-text">往期测评</text>
</view>
<view class="menu-grid-item" @click="handleContactUs">
<view class="menu-icon-wrapper contact">
<text class="menu-icon-text">📞</text>
</view>
<text class="menu-text">联系我们</text>
</view>
<view class="menu-grid-item" v-if="isPartner" @click="goInvite">
<view class="menu-icon-wrapper invite">
<text class="menu-icon-text">👥</text>
</view>
<text class="menu-text">邀请新用户</text>
</view>
</view>
</view>
<!-- 其他功能区域 -->
<view class="menu-section">
<view class="section-title">其他</view>
<view class="menu-list">
<view class="menu-item" @click="goAbout">
<text class="menu-title">关于</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="goUserAgreement">
<text class="menu-title">用户协议</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="goPrivacyPolicy">
<text class="menu-title">隐私政策</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item logout-item" v-if="isLoggedIn" @click="showLogoutPopup">
<text class="menu-title logout-text">退出登录</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>
</template>
<script setup>
/**
* 我的页面
* 展示用户信息和功能入口
*/
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/user.js'
import { useNavbar } from '@/composables/useNavbar.js'
const userStore = useUserStore()
const { statusBarHeight, navbarHeight, totalNavbarHeight } = useNavbar()
// 退出登录弹窗状态
const logoutPopupVisible = ref(false)
// 计算属性
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
}))
// 导航栏样式
const navbarStyle = computed(() => ({
paddingTop: statusBarHeight.value + 'px',
height: totalNavbarHeight.value + 'px'
}))
/**
* 跳转登录页
*/
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'
})
}
/**
* 联系我们
*/
function handleContactUs() {
// 调用微信客服
// 如果没有配置客服,可以显示联系方式
uni.showModal({
title: '联系我们',
content: '如有问题请联系客服微信xxxxxx',
showCancel: false,
confirmText: '我知道了'
})
}
/**
* 跳转邀请新用户
*/
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(() => {
userStore.restoreFromStorage()
})
/**
* 页面加载
*/
onMounted(() => {
userStore.restoreFromStorage()
})
</script>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.mine-page {
min-height: 100vh;
background-color: $bg-color;
}
// 自定义导航栏
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: $bg-white;
z-index: 999;
.navbar-content {
display: flex;
align-items: center;
justify-content: center;
.navbar-title {
font-size: 34rpx;
font-weight: $font-weight-medium;
color: $text-color;
}
}
}
.navbar-placeholder {
width: 100%;
}
// 页面内容
.page-content {
padding: $spacing-lg;
padding-bottom: env(safe-area-inset-bottom);
}
// 用户信息区域
.user-section {
margin-bottom: $spacing-lg;
.user-card {
background-color: $bg-white;
border-radius: $border-radius-lg;
padding: $spacing-lg;
display: flex;
align-items: center;
.avatar-wrapper {
margin-right: $spacing-lg;
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
background-color: $bg-gray;
}
}
.user-info {
flex: 1;
}
// 未登录状态
&.not-logged {
.user-info {
display: flex;
flex-direction: column;
align-items: flex-start;
.login-tip {
font-size: $font-size-md;
color: $text-secondary;
margin-bottom: $spacing-sm;
}
.btn-login {
width: 180rpx;
height: 64rpx;
line-height: 64rpx;
background-color: $primary-color;
border-radius: 32rpx;
font-size: $font-size-sm;
color: $text-white;
border: none;
padding: 0;
margin: 0;
&::after {
border: none;
}
&:active {
opacity: 0.8;
}
}
}
}
// 已登录状态
&.logged {
.user-info {
display: flex;
flex-direction: column;
.nickname {
font-size: $font-size-lg;
font-weight: $font-weight-medium;
color: $text-color;
margin-bottom: 8rpx;
}
.uid {
font-size: $font-size-sm;
color: $text-placeholder;
}
}
.arrow-icon {
.iconfont {
font-size: 40rpx;
color: $text-placeholder;
}
}
}
}
}
// 菜单区域
.menu-section {
background-color: $bg-white;
border-radius: $border-radius-lg;
margin-bottom: $spacing-lg;
overflow: hidden;
.section-title {
font-size: $font-size-md;
font-weight: $font-weight-medium;
color: $text-color;
padding: $spacing-lg $spacing-lg $spacing-sm;
}
// 网格菜单
.menu-grid {
display: flex;
flex-wrap: wrap;
padding: $spacing-sm $spacing-lg $spacing-lg;
.menu-grid-item {
width: 25%;
display: flex;
flex-direction: column;
align-items: center;
padding: $spacing-md 0;
&:active {
opacity: 0.7;
}
.menu-icon-wrapper {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: $spacing-xs;
&.order {
background-color: rgba(74, 144, 226, 0.1);
}
&.history {
background-color: rgba(82, 196, 26, 0.1);
}
&.contact {
background-color: rgba(250, 173, 20, 0.1);
}
&.invite {
background-color: rgba(255, 77, 79, 0.1);
}
.menu-icon-text {
font-size: 40rpx;
}
}
.menu-icon {
width: 56rpx;
height: 56rpx;
margin-bottom: $spacing-xs;
}
.menu-text {
font-size: $font-size-xs;
color: $text-color;
}
}
}
// 列表菜单
.menu-list {
.menu-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-lg;
border-bottom: 1rpx solid $border-light;
&:last-child {
border-bottom: none;
}
&:active {
background-color: $bg-gray;
}
.menu-title {
font-size: $font-size-md;
color: $text-color;
}
.menu-arrow {
font-size: 32rpx;
color: $text-placeholder;
}
&.logout-item {
.logout-text {
color: $error-color;
}
}
}
}
}
// 底部安全区域
.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;
}
}
}
}
}
</style>