Some checks reported errors
continuous-integration/drone/push Build encountered an error
444 lines
11 KiB
Vue
444 lines
11 KiB
Vue
<template>
|
||
<view class="mine-page">
|
||
<!-- 自定义头部 -->
|
||
<view class="header" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="header-inner">
|
||
<text class="header-title">贩卖机</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 用户信息区域 -->
|
||
<view class="user-section" :style="{ marginTop: (statusBarHeight + 44) + 'px' }">
|
||
<!-- 未登录状态 -->
|
||
<view v-if="!userStore.isLoggedIn" class="user-row" @click="goLogin">
|
||
<image class="avatar" src="/static/logo.png" mode="aspectFill" />
|
||
<text class="login-btn-text">注册/登录 ></text>
|
||
</view>
|
||
<!-- 已登录状态 -->
|
||
<view v-else class="user-row">
|
||
<image class="avatar" src="/static/logo.png" mode="aspectFill" />
|
||
<view class="user-info">
|
||
<view class="name-row">
|
||
<text class="nickname">{{ userStore.userInfo?.nickname || '' }}</text>
|
||
<view v-if="userStore.userInfo?.isMember" class="vip-tag">
|
||
<image class="vip-icon" src="/static/ic_vip.png" mode="aspectFit" />
|
||
<text class="vip-text">会员</text>
|
||
</view>
|
||
</view>
|
||
<text class="uid">UID:{{ userStore.userInfo?.uid || '' }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 积分区域 -->
|
||
<view v-if="userStore.isLoggedIn" class="points-card" @click="goPoints">
|
||
<view class="points-left">
|
||
<view class="points-icon-wrap">
|
||
<image class="points-icon" src="/static/ic_integral.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="points-label">{{ t('mine.points') }}</text>
|
||
</view>
|
||
<text class="points-value">{{ balance }}</text>
|
||
</view>
|
||
|
||
<!-- 功能入口(赠送积分 + 我的优惠券) -->
|
||
<view v-if="userStore.isLoggedIn" class="func-row">
|
||
<view class="func-card" @click="showGiftPopup = true">
|
||
<view class="func-icon-wrap gift-bg">
|
||
<image class="func-icon" src="/static/ic_reward_points.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="func-label">{{ t('mine.giftPoints') }}</text>
|
||
</view>
|
||
<view class="func-card" @click="goCoupons">
|
||
<view class="func-icon-wrap coupon-bg">
|
||
<image class="func-icon" src="/static/ic_my_coupon.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="func-label">{{ t('mine.myCoupons') }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 菜单列表 -->
|
||
<view class="menu-card">
|
||
<view class="menu-item" @click="showLangPicker = true">
|
||
<view class="menu-icon-wrap">
|
||
<image class="menu-icon" src="/static/ic_language.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="menu-text">{{ t('mine.switchLang') }}</text>
|
||
<text class="menu-extra">{{ currentLangLabel }}</text>
|
||
<text class="menu-arrow">›</text>
|
||
</view>
|
||
<view class="menu-item" @click="goAgreement">
|
||
<view class="menu-icon-wrap">
|
||
<image class="menu-icon" src="/static/ic_agreement.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="menu-text">{{ t('mine.userAgreement') }}</text>
|
||
<text class="menu-arrow">›</text>
|
||
</view>
|
||
<view class="menu-item" @click="goPrivacy">
|
||
<view class="menu-icon-wrap">
|
||
<image class="menu-icon" src="/static/ic_agreement2.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="menu-text">{{ t('mine.privacyPolicy') }}</text>
|
||
<text class="menu-arrow">›</text>
|
||
</view>
|
||
<view class="menu-item" @click="goAbout">
|
||
<view class="menu-icon-wrap">
|
||
<image class="menu-icon" src="/static/ic_about.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="menu-text">{{ t('mine.about') }}</text>
|
||
<text class="menu-arrow">›</text>
|
||
</view>
|
||
<view v-if="userStore.isLoggedIn" class="menu-item" @click="showLogoutConfirm = true">
|
||
<view class="menu-icon-wrap">
|
||
<image class="menu-icon" src="/static/ic_exit.png" mode="aspectFit" />
|
||
</view>
|
||
<text class="menu-text">{{ t('mine.logout') }}</text>
|
||
<text class="menu-arrow">›</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 退出登录确认弹窗 -->
|
||
<view class="popup-mask" v-if="showLogoutConfirm" @click="showLogoutConfirm = false">
|
||
<view class="popup-content" @click.stop>
|
||
<text class="popup-title">{{ t('mine.logoutConfirm') }}</text>
|
||
<view class="popup-actions">
|
||
<view class="btn cancel-btn" @click="showLogoutConfirm = false">
|
||
<text class="btn-text cancel-text">{{ t('common.cancel') }}</text>
|
||
</view>
|
||
<view class="btn confirm-btn" @click="handleLogout">
|
||
<text class="btn-text confirm-text">{{ t('common.confirm') }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 赠送积分弹窗 -->
|
||
<GiftPointsPopup :visible="showGiftPopup" @close="showGiftPopup = false" @success="loadBalance" />
|
||
|
||
<!-- 语言选择器弹窗 -->
|
||
<LanguagePicker :visible="showLangPicker" @close="showLangPicker = false" />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useI18n } from 'vue-i18n'
|
||
import { useUserStore } from '../../stores/user.js'
|
||
import { getBalance } from '../../api/points.js'
|
||
import { getStorage, LOCALE_KEY } from '../../utils/storage.js'
|
||
import GiftPointsPopup from '../../components/GiftPointsPopup.vue'
|
||
import LanguagePicker from '../../components/LanguagePicker.vue'
|
||
|
||
const { t, locale } = useI18n()
|
||
const userStore = useUserStore()
|
||
|
||
// 状态栏高度
|
||
const statusBarHeight = ref(0)
|
||
try {
|
||
const sysInfo = uni.getSystemInfoSync()
|
||
statusBarHeight.value = sysInfo.statusBarHeight || 0
|
||
} catch (e) {}
|
||
|
||
// 积分余额
|
||
const balance = ref(0)
|
||
|
||
// 弹窗状态
|
||
const showGiftPopup = ref(false)
|
||
const showLangPicker = ref(false)
|
||
const showLogoutConfirm = ref(false)
|
||
|
||
// 当前语言标签
|
||
const currentLangLabel = computed(() => {
|
||
const map = { 'zh-CN': '简体中文', 'zh-TW': '繁體中文', 'en': 'English' }
|
||
return map[locale.value] || '简体中文'
|
||
})
|
||
|
||
// 加载积分余额
|
||
async function loadBalance() {
|
||
if (!userStore.isLoggedIn) return
|
||
try {
|
||
const res = await getBalance()
|
||
balance.value = res.data?.balance ?? res.data ?? 0
|
||
} catch (e) {}
|
||
}
|
||
|
||
// 退出登录
|
||
async function handleLogout() {
|
||
showLogoutConfirm.value = false
|
||
await userStore.logout()
|
||
balance.value = 0
|
||
// 清除所有页面栈,返回首页
|
||
uni.reLaunch({ url: '/pages/index/index' })
|
||
}
|
||
|
||
// 页面导航
|
||
function goLogin() { uni.navigateTo({ url: '/pages/login/login' }) }
|
||
function goPoints() { uni.navigateTo({ url: '/pages/points/points' }) }
|
||
function goCoupons() { uni.navigateTo({ url: '/pages/coupons/coupons' }) }
|
||
function goAgreement() { uni.navigateTo({ url: '/pages/agreement/agreement' }) }
|
||
function goPrivacy() { uni.navigateTo({ url: '/pages/privacy/privacy' }) }
|
||
function goAbout() { uni.navigateTo({ url: '/pages/about/about' }) }
|
||
|
||
onMounted(() => {
|
||
if (userStore.isLoggedIn) {
|
||
userStore.fetchUserInfo()
|
||
loadBalance()
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.mine-page {
|
||
min-height: 100vh;
|
||
background-color: #f5f0e8;
|
||
}
|
||
|
||
/* 自定义头部 */
|
||
.header {
|
||
position: fixed;
|
||
top: 0; left: 0; right: 0;
|
||
z-index: 100;
|
||
background-color: #f5f0e8;
|
||
}
|
||
.header-inner {
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.header-title {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
/* 用户信息 */
|
||
.user-section {
|
||
padding: 30rpx 30rpx 0;
|
||
}
|
||
.user-row {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.avatar {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 50rpx;
|
||
margin-right: 20rpx;
|
||
background-color: #e0e0e0;
|
||
}
|
||
.login-btn-text {
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
.user-info {
|
||
flex: 1;
|
||
}
|
||
.name-row {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
.nickname {
|
||
font-size: 34rpx;
|
||
color: #333;
|
||
font-weight: 600;
|
||
margin-right: 12rpx;
|
||
}
|
||
.vip-tag {
|
||
display: flex;
|
||
align-items: center;
|
||
background-color: #4a5d4a;
|
||
border-radius: 20rpx;
|
||
padding: 4rpx 16rpx 4rpx 8rpx;
|
||
}
|
||
.vip-icon {
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
margin-right: 4rpx;
|
||
}
|
||
.vip-text {
|
||
font-size: 22rpx;
|
||
color: #ffffff;
|
||
}
|
||
.uid {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
/* 积分卡片 */
|
||
.points-card {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background-color: #ffffff;
|
||
margin: 24rpx 24rpx 0;
|
||
padding: 28rpx 32rpx;
|
||
border-radius: 20rpx;
|
||
}
|
||
.points-left {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.points-icon-wrap {
|
||
width: 72rpx;
|
||
height: 72rpx;
|
||
border-radius: 50%;
|
||
background-color: #f5f0e8;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 16rpx;
|
||
}
|
||
.points-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
.points-label {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
}
|
||
.points-value {
|
||
font-size: 40rpx;
|
||
color: #333;
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* 功能入口行 */
|
||
.func-row {
|
||
display: flex;
|
||
padding: 24rpx 24rpx 0;
|
||
gap: 24rpx;
|
||
}
|
||
.func-card {
|
||
flex: 1;
|
||
background-color: #ffffff;
|
||
border-radius: 20rpx;
|
||
padding: 32rpx 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
.func-icon-wrap {
|
||
width: 72rpx;
|
||
height: 72rpx;
|
||
border-radius: 18rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
.gift-bg {
|
||
background-color: #f5f0e8;
|
||
}
|
||
.coupon-bg {
|
||
background-color: #f5f0e8;
|
||
}
|
||
.func-icon {
|
||
width: 44rpx;
|
||
height: 44rpx;
|
||
}
|
||
.func-label {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
/* 菜单列表 */
|
||
.menu-card {
|
||
background-color: #ffffff;
|
||
margin: 24rpx 24rpx 0;
|
||
border-radius: 20rpx;
|
||
overflow: hidden;
|
||
}
|
||
.menu-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 30rpx 32rpx;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
}
|
||
.menu-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.menu-icon-wrap {
|
||
width: 72rpx;
|
||
height: 72rpx;
|
||
border-radius: 16rpx;
|
||
background-color: #eeeeee;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 20rpx;
|
||
}
|
||
.menu-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
.menu-text {
|
||
flex: 1;
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
}
|
||
.menu-extra {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
margin-right: 8rpx;
|
||
}
|
||
.menu-arrow {
|
||
font-size: 32rpx;
|
||
color: #ccc;
|
||
}
|
||
|
||
/* 弹窗样式 */
|
||
.popup-mask {
|
||
position: fixed;
|
||
top: 0; left: 0; right: 0; bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 999;
|
||
}
|
||
.popup-content {
|
||
width: 600rpx;
|
||
background-color: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 40rpx;
|
||
}
|
||
.popup-title {
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
text-align: center;
|
||
display: block;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
.popup-actions {
|
||
display: flex;
|
||
gap: 20rpx;
|
||
}
|
||
.btn {
|
||
flex: 1;
|
||
height: 84rpx;
|
||
border-radius: 12rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.cancel-btn {
|
||
background-color: #ffffff;
|
||
border: 2rpx solid #6b7c5e;
|
||
}
|
||
.confirm-btn {
|
||
background-color: #6b7c5e;
|
||
}
|
||
.btn-text {
|
||
font-size: 30rpx;
|
||
}
|
||
.cancel-text {
|
||
color: #6b7c5e;
|
||
}
|
||
.confirm-text {
|
||
color: #ffffff;
|
||
}
|
||
</style>
|