437 lines
9.0 KiB
Vue
437 lines
9.0 KiB
Vue
<template>
|
||
<view class="user-page" :style="{ paddingTop: getNotchHeight() + 30 + 'px' }">
|
||
<!-- 设置图标 -->
|
||
<view class="settings-icon" :style="{ top: getNotchHeight() + 30 + 'px' }" @click="goSettings">
|
||
<wd-icon name="setting1" size="24px" color="#666" />
|
||
<text>{{ $t('user.settings') }}</text>
|
||
</view>
|
||
|
||
<!-- 用户信息区域 -->
|
||
<view class="user-info-section">
|
||
<view class="user-info">
|
||
<image :src="userInfo.avatar || defaultAvatar" class="avatar" @click="goProfile" />
|
||
<view class="user-details">
|
||
<text class="nickname">{{ userInfo.nickname || $t('user.notSet') }}</text>
|
||
<text v-if="userInfo.email" class="email">{{ userInfo.email }}</text>
|
||
<text v-if="vipInfo.endTime && platform === 'ios'" class="vip-time">
|
||
VIP {{ vipInfo.endTime.split(' ')[0] }} {{ $t('user.vipExpireTime') }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- VIP订阅卡片 -->
|
||
<view class="vip-card-section">
|
||
<view class="vip-card">
|
||
<view class="vip-card-title">{{ $t('user.vip') }}</view>
|
||
<view class="vip-card-content">
|
||
<view class="vip-item-list">
|
||
<view v-if="vipInfo.length > 0" v-for="vip in vipInfo">{{ vipTypeDict[vip.type] }}(有效期到
|
||
{{ parseTime(vip.endTime, '{y}-{m}-{d}') }})</view>
|
||
<view v-else>办理课程VIP,畅享更多权益</view>
|
||
</view>
|
||
<wd-button v-if="vipInfo.length > 0" plain type="primary" size="small"
|
||
@click="goSubscribe">{{ $t('vip.renewal') }}</wd-button>
|
||
<wd-button v-else plain type="primary" size="small" @click="goSubscribe">{{ $t('vip.openVip') }}</wd-button>
|
||
</view>
|
||
<view class="vip-card-content">
|
||
<view class="vip-item-list">
|
||
<view v-if="vipInfoEbook.length > 0" v-for="vip in vipInfoEbook">电子书VIP{{ vipTypeDict[vip.type] }}(有效期到
|
||
{{ parseTime(vip.endTime, '{y}-{m}-{d}') }})</view>
|
||
<view v-else>办理电子书VIP,畅享更多权益</view>
|
||
</view>
|
||
<wd-button v-if="!vipInfoEbook.length" plain type="primary" size="small"
|
||
@click="goSubscribe">{{ $t('vip.openVip') }}</wd-button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 我的资产 -->
|
||
<view class="assets-card-section wallet-section">
|
||
<view class="assets-card wallet_l">
|
||
<view class="assets">
|
||
<view @click="goVirtualList">
|
||
<view class="assets_row">{{ t('global.coin') }}</view>
|
||
<view>{{userInfo.peanutCoin ?? 1}}</view>
|
||
</view>
|
||
<view @click="goPointsList">
|
||
<view class="assets_row">积分</view>
|
||
<view>{{userInfo.jf ?? 1}}</view>
|
||
</view>
|
||
<!-- <view>
|
||
<view class="assets_row">优惠卷</view>
|
||
<view>0</view>
|
||
</view> -->
|
||
</view>
|
||
<view class="chong_btn" @click="goRecharge">充 值</view>
|
||
<!-- <text class="wallet_title">{{$t('my.coin')}}<uni-icons type="help" size="19" color="#666"></uni-icons></text>
|
||
<text class="wallet_count">{{userMes.peanutCoin}}</text> -->
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 功能菜单列表 -->
|
||
<view class="menu-section">
|
||
<view class="menu-list">
|
||
<view v-for="item in menuItems" :key="item.id" class="menu-item" @click="handleMenuClick(item)">
|
||
<text class="menu-text">{{ item.name }}</text>
|
||
<wd-icon name="arrow-right" size="16px" color="#aaa" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useUserStore } from '@/stores/user'
|
||
import { useSysStore } from '@/stores/sys'
|
||
import { getUserInfo, getVipInfo } from '@/api/modules/user'
|
||
import type { IVipInfo } from '@/types/user'
|
||
import { getNotchHeight } from '@/utils/system'
|
||
import { parseTime } from '@/utils/index'
|
||
import { t } from '@/utils/i18n'
|
||
import { onShow } from '@dcloudio/uni-app'
|
||
|
||
const userStore = useUserStore()
|
||
const sysStore = useSysStore()
|
||
|
||
// 默认头像
|
||
const defaultAvatar = '/static/home_icon.png'
|
||
|
||
// 用户信息
|
||
const userInfo = computed(() => userStore.userInfo)
|
||
|
||
// VIP信息
|
||
const vipInfo = computed(() => userStore.userVips)
|
||
const vipInfoEbook = computed(() => userStore.userEbookVip)
|
||
|
||
// VIP类型字典
|
||
const vipTypeDict = sysStore.vipTypeDict
|
||
|
||
// 平台信息
|
||
const platform = ref('')
|
||
|
||
// 菜单项
|
||
const menuItems = computed(() => [
|
||
{
|
||
id: 1,
|
||
name: t('user.myOrders'),
|
||
url: '/pages/user/order/index',
|
||
type: 'pageJump'
|
||
},
|
||
{
|
||
id: 2,
|
||
name: t('user.myBooklist'),
|
||
url: '/pages/user/myBook/index',
|
||
type: 'pageJump'
|
||
},
|
||
{
|
||
id: 3,
|
||
name: t('user.profile'),
|
||
url: '/pages/user/profile/index',
|
||
type: 'pageJump'
|
||
},
|
||
{
|
||
id: 4,
|
||
name: t('user.about'),
|
||
url: '/pages/user/about/index',
|
||
type: 'pageJump'
|
||
},
|
||
{
|
||
id: 5,
|
||
name: t('user.feedback'),
|
||
url: '/pages/user/feedback/index',
|
||
type: 'pageJump'
|
||
}
|
||
])
|
||
|
||
/**
|
||
* 获取平台信息
|
||
*/
|
||
const getPlatform = () => {
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
platform.value = systemInfo.platform === 'android' ? 'android' : 'ios'
|
||
}
|
||
|
||
/**
|
||
* 获取数据
|
||
*/
|
||
const getData = async () => {
|
||
// 获取用户信息
|
||
const userInfoRes = await getUserInfo()
|
||
if (userInfoRes.result) {
|
||
userStore.setUserInfo(userInfoRes.result)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 跳转到设置页面
|
||
*/
|
||
const goSettings = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/user/settings/index'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 跳转到个人资料页面
|
||
*/
|
||
const goProfile = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/user/profile/index'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 跳转到订阅页面
|
||
*/
|
||
const goSubscribe = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/vip/book'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 处理菜单点击
|
||
*/
|
||
const handleMenuClick = (item : any) => {
|
||
switch (item.type) {
|
||
case 'pageJump':
|
||
uni.navigateTo({
|
||
url: item.url
|
||
})
|
||
break
|
||
case 'switchTab':
|
||
uni.switchTab({
|
||
url: item.url
|
||
})
|
||
break
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 跳转充值页面
|
||
*/
|
||
const goRecharge = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/user/recharge/index'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 跳转虚拟币页面
|
||
*/
|
||
const goVirtualList = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/user/virtual/index'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 跳转积分列表
|
||
*/
|
||
const goPointsList = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/user/points/index'
|
||
})
|
||
}
|
||
|
||
onShow(() => {
|
||
getData()
|
||
})
|
||
|
||
onMounted(() => {
|
||
getPlatform()
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
$theme-color: #54a966;
|
||
|
||
.user-page {
|
||
min-height: 100vh;
|
||
background-color: #f7faf9;
|
||
}
|
||
|
||
.settings-icon {
|
||
position: absolute;
|
||
right: 20px;
|
||
z-index: 2;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
line-height: 1.2;
|
||
|
||
text {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.user-info-section {
|
||
padding: 0 30rpx;
|
||
margin-bottom: 50rpx;
|
||
}
|
||
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.avatar {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 100rpx;
|
||
margin-right: 30rpx;
|
||
}
|
||
|
||
.user-details {
|
||
flex: 1;
|
||
|
||
.nickname {
|
||
display: block;
|
||
font-size: 38rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.email {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.vip-time {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
}
|
||
}
|
||
|
||
// vip 卡片
|
||
.vip-card-section {
|
||
padding: 0 20rpx;
|
||
margin-bottom: 20rpx;
|
||
|
||
.vip-card {
|
||
background: linear-gradient(135deg, #3E7EF5 0%, #9134EA 100%);
|
||
border-radius: 15rpx;
|
||
padding: 26rpx 30rpx 10rpx;
|
||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||
|
||
.vip-card-title {
|
||
font-size: 32rpx;
|
||
color: #fff;
|
||
font-weight: bold;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.vip-card-content {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background-color: rgba(255, 255, 255, 0.2);
|
||
border-radius: 8px;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.vip-item-list {
|
||
font-size: 28rpx;
|
||
color: #fff;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
|
||
.assets-card-section {
|
||
padding: 0 20rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.assets-card {
|
||
background: #fff;
|
||
border-radius: 15rpx;
|
||
padding: 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||
|
||
.assets-info {
|
||
text-align: center;
|
||
|
||
.label {
|
||
display: block;
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.value {
|
||
display: block;
|
||
font-size: 30rpx;
|
||
color: $theme-color;
|
||
}
|
||
}
|
||
}
|
||
|
||
.menu-section {
|
||
padding: 20rpx 20rpx 0;
|
||
}
|
||
|
||
.menu-list {
|
||
background: #fff;
|
||
border-radius: 15rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.menu-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 30rpx;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
&:active {
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.menu-text {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
line-height: 40rpx;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
.chong_btn {
|
||
font-size: 26rpx;
|
||
display: block;
|
||
border-radius: 50rpx;
|
||
color: #fffbf6;
|
||
padding: 10rpx 32rpx;
|
||
background-image: linear-gradient(90deg, #3ab3ae 0%, #d5ecdd 200%);
|
||
}
|
||
|
||
.assets {
|
||
display: flex;
|
||
flex: 1;
|
||
justify-content: space-around;
|
||
text-align: center;
|
||
transform: translateX(-20px);
|
||
|
||
.assets_row {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
}
|
||
</style> |