496 lines
11 KiB
Vue
496 lines
11 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="my">
|
|||
|
|
<!-- 用户信息区域 -->
|
|||
|
|
<view class="user-info">
|
|||
|
|
<view class="background">
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
<view class="info-content">
|
|||
|
|
<view class="top-user-name" :style="{'height': topHeight, 'line-height': topHeight}">
|
|||
|
|
{{userInfo.nickName}}
|
|||
|
|
</view>
|
|||
|
|
<view class="avatars">
|
|||
|
|
<image class="avatar-img" :src="userInfo.avatarUrl ? userInfo.avatarUrl : 'https://pic.rmb.bdstatic.com/bjh/down/1742bc3845cbbcf0c78c01eb59bb1c1a.jpeg'" @click="updateAvatar"></image>
|
|||
|
|
</view>
|
|||
|
|
<view class="hello-text">
|
|||
|
|
<p>你好,{{userInfo.nickName}}</p>
|
|||
|
|
<p>欢迎使用计分小程序</p>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 数据统计区域 -->
|
|||
|
|
<view class="data-section">
|
|||
|
|
<view class="data-item" @click="navigateToHistory">
|
|||
|
|
<text class="data-label">总对局数</text>
|
|||
|
|
<text class="data-number">{{totalGames || 0}}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="data-divider"></view>
|
|||
|
|
<view class="data-item" @click="navigateToHistory">
|
|||
|
|
<text class="data-label">胜利局数</text>
|
|||
|
|
<text class="data-number">{{totalWins || 0}}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="data-divider"></view>
|
|||
|
|
<view class="data-item" @click="navigateToHistory">
|
|||
|
|
<text class="data-label">胜率</text>
|
|||
|
|
<text class="data-number">{{winRate || '0%'}}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 功能菜单区域 -->
|
|||
|
|
<view class="menu-section">
|
|||
|
|
<!-- 第一组菜单 -->
|
|||
|
|
<view class="menu-group">
|
|||
|
|
|
|||
|
|
<view class="menu-item" @click="navigateToFavorites">
|
|||
|
|
<view class="menu-left">
|
|||
|
|
<image src="/static/favorites.png" alt="收藏的对局" class="menu-icon" mode="aspectFit"></image>
|
|||
|
|
<text class="menu-text">收藏的对局</text>
|
|||
|
|
</view>
|
|||
|
|
<uni-icons type="right" size="24" color="#999"></uni-icons>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 第二组菜单 -->
|
|||
|
|
<view class="menu-group">
|
|||
|
|
<view class="menu-item" @click="openSettings">
|
|||
|
|
<view class="menu-left">
|
|||
|
|
<image src="/static/setting.png" alt="设置" class="menu-icon" mode="aspectFit"></image>
|
|||
|
|
<text class="menu-text">设置</text>
|
|||
|
|
</view>
|
|||
|
|
<uni-icons type="right" size="24" color="#999"></uni-icons>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="menu-item" @click="openFeedback">
|
|||
|
|
<view class="menu-left">
|
|||
|
|
<image src="/static/feedback.png" alt="帮助与反馈" class="menu-icon" mode="aspectFit"></image>
|
|||
|
|
<text class="menu-text">帮助与反馈</text>
|
|||
|
|
</view>
|
|||
|
|
<uni-icons type="right" size="24" color="#999"></uni-icons>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="menu-item" @click="aboutUs">
|
|||
|
|
<view class="menu-left">
|
|||
|
|
<image src="/static/about.png" alt="关于我们" class="menu-icon" mode="aspectFit"></image>
|
|||
|
|
<text class="menu-text">关于我们</text>
|
|||
|
|
</view>
|
|||
|
|
<uni-icons type="right" size="24" color="#999"></uni-icons>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 版本信息 -->
|
|||
|
|
<view class="version-info">
|
|||
|
|
<text>版本 {{version || '1.0.0'}}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { onMounted, onUnmounted, ref, getCurrentInstance } from 'vue'
|
|||
|
|
import { onLoad, onShow, onHide } from '@dcloudio/uni-app'
|
|||
|
|
import { getOpenId } from '@/utils/wxutils.js'
|
|||
|
|
import { register, login } from '@/api/user.js'
|
|||
|
|
|
|||
|
|
const proxy = getCurrentInstance().proxy;
|
|||
|
|
|
|||
|
|
// 小程序胶囊高度
|
|||
|
|
const topHeight = ref(proxy.$StaticValue.getTopHeight());
|
|||
|
|
|
|||
|
|
// 用户信息相关
|
|||
|
|
const userInfo = ref({});
|
|||
|
|
const totalGames = ref(0);
|
|||
|
|
const totalWins = ref(0);
|
|||
|
|
const winRate = ref('0%');
|
|||
|
|
const unreadCount = ref(0);
|
|||
|
|
const version = ref('1.0.0');
|
|||
|
|
|
|||
|
|
// 获取用户信息
|
|||
|
|
const getUserInfo = async () => {
|
|||
|
|
// 从本地获取用户信息
|
|||
|
|
userInfo.value = proxy.$StaticValue.getUserInfo();
|
|||
|
|
if(!userInfo.value?.userId) {
|
|||
|
|
// 如果没有登录, 获取到当前用户的openid
|
|||
|
|
const openIdRes = await getOpenId();
|
|||
|
|
const openId = openIdRes.openid;
|
|||
|
|
userInfo.value = {
|
|||
|
|
openId: openId,
|
|||
|
|
nickName: '用户'+openId.substring(0, 6)
|
|||
|
|
};
|
|||
|
|
register(userInfo.value).then(res => {
|
|||
|
|
// 注册成功就执行登录
|
|||
|
|
login(userInfo.value).then(loginRes => {
|
|||
|
|
userInfo.value = loginRes.data;
|
|||
|
|
// 存储用户信息到本地
|
|||
|
|
proxy.$StaticValue.setUserInfo(userInfo.value);
|
|||
|
|
// 获取用户统计数据
|
|||
|
|
fetchUserStats();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
// 已登录,获取用户统计数据
|
|||
|
|
fetchUserStats();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取用户统计数据
|
|||
|
|
const fetchUserStats = () => {
|
|||
|
|
// 实际项目中应该调用API获取真实数据
|
|||
|
|
// 这里使用模拟数据
|
|||
|
|
totalGames.value = 42;
|
|||
|
|
totalWins.value = 28;
|
|||
|
|
winRate.value = '66.7%';
|
|||
|
|
unreadCount.value = 2;
|
|||
|
|
|
|||
|
|
// 实际API调用示例:
|
|||
|
|
// getUserStats(userInfo.value.userId).then(res => {
|
|||
|
|
// totalGames.value = res.data.totalGames;
|
|||
|
|
// totalWins.value = res.data.totalWins;
|
|||
|
|
// winRate.value = res.data.winRate;
|
|||
|
|
// unreadCount.value = res.data.unreadCount;
|
|||
|
|
// });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新头像
|
|||
|
|
const updateAvatar = () => {
|
|||
|
|
/* #ifdef MP-WEIXIN */
|
|||
|
|
wx.chooseMedia({
|
|||
|
|
count: 1,
|
|||
|
|
mediaType: ['image'],
|
|||
|
|
sourceType: ['album', 'camera'],
|
|||
|
|
sizeType: ['compressed'],
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.tempFiles && res.tempFiles.length > 0) {
|
|||
|
|
const tempFilePath = res.tempFiles[0].tempFilePath;
|
|||
|
|
|
|||
|
|
// 预览选择的头像
|
|||
|
|
wx.previewImage({
|
|||
|
|
urls: [tempFilePath],
|
|||
|
|
success: () => {
|
|||
|
|
// 更新头像
|
|||
|
|
userInfo.value.avatarUrl = tempFilePath;
|
|||
|
|
// 在实际项目中应该上传头像到服务器
|
|||
|
|
proxy.$StaticValue.setUserInfo(userInfo.value);
|
|||
|
|
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '头像更新成功',
|
|||
|
|
icon: 'success'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
fail: (err) => {
|
|||
|
|
console.log('选择头像失败', err);
|
|||
|
|
if (err.errMsg !== 'chooseMedia:fail cancel') {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '选择头像失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
/* #endif */
|
|||
|
|
|
|||
|
|
/* #ifndef MP-WEIXIN */
|
|||
|
|
uni.chooseImage({
|
|||
|
|
count: 1,
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
|
|||
|
|
userInfo.value.avatarUrl = res.tempFilePaths[0];
|
|||
|
|
proxy.$StaticValue.setUserInfo(userInfo.value);
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '头像更新成功',
|
|||
|
|
icon: 'success'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
/* #endif */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 导航到历史对局页面
|
|||
|
|
const navigateToHistory = () => {
|
|||
|
|
uni.navigateTo({
|
|||
|
|
url: '/pages/history-game/history-game'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 导航到收藏对局页面
|
|||
|
|
const navigateToFavorites = () => {
|
|||
|
|
// 如果收藏页面不存在,可以创建一个或跳转到历史页面并筛选
|
|||
|
|
uni.navigateTo({
|
|||
|
|
url: '/pages/my/favorites'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开设置页面
|
|||
|
|
const openSettings = () => {
|
|||
|
|
uni.navigateTo({
|
|||
|
|
url: '/pages/my/setting'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开帮助与反馈
|
|||
|
|
const openFeedback = () => {
|
|||
|
|
uni.navigateTo({
|
|||
|
|
url: '/pages/my/feedback'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 关于我们
|
|||
|
|
const aboutUs = () => {
|
|||
|
|
uni.showModal({
|
|||
|
|
title: '关于计分小程序',
|
|||
|
|
content: '计分小程序 v' + version.value + '\n\n一款便捷的计分工具,支持多种游戏模式。\n\n© 2023 计分小程序团队',
|
|||
|
|
showCancel: false,
|
|||
|
|
confirmText: '确定'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 退出登录
|
|||
|
|
const logout = () => {
|
|||
|
|
uni.showModal({
|
|||
|
|
title: '确认退出',
|
|||
|
|
content: '确定要退出登录吗?',
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.confirm) {
|
|||
|
|
// 清除本地存储的用户信息
|
|||
|
|
proxy.$StaticValue.clearUserInfo();
|
|||
|
|
// 重置用户信息
|
|||
|
|
userInfo.value = {};
|
|||
|
|
totalGames.value = 0;
|
|||
|
|
totalWins.value = 0;
|
|||
|
|
winRate.value = '0%';
|
|||
|
|
|
|||
|
|
// 重新获取用户信息(会自动重新登录)
|
|||
|
|
getUserInfo();
|
|||
|
|
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '已退出登录',
|
|||
|
|
icon: 'success'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
onMounted(() => {
|
|||
|
|
getUserInfo();
|
|||
|
|
// 获取版本信息
|
|||
|
|
/* #ifdef MP-WEIXIN */
|
|||
|
|
const appInfo = wx.getAccountInfoSync();
|
|||
|
|
version.value = appInfo.miniProgram.version || '1.0.0';
|
|||
|
|
/* #endif */
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
onShow(() => {
|
|||
|
|
// 每次显示页面时刷新数据
|
|||
|
|
fetchUserStats();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="less" scoped>
|
|||
|
|
.my {
|
|||
|
|
width: 750rpx;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
min-height: 100vh;
|
|||
|
|
background-color: #f8f8f8;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 用户信息区域样式 */
|
|||
|
|
.user-info {
|
|||
|
|
--user-height: 500rpx;
|
|||
|
|
width: 750rpx;
|
|||
|
|
height: var(--user-height);
|
|||
|
|
position: relative;
|
|||
|
|
.background {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
background-image: linear-gradient(rgb(87, 255, 87), rgb(144, 251, 144));
|
|||
|
|
position: absolute;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
z-index: 0;
|
|||
|
|
}
|
|||
|
|
.info-content {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
position: relative;
|
|||
|
|
z-index: 1;
|
|||
|
|
padding-top: calc(var(--top-margin) + 20rpx);
|
|||
|
|
.top-user-name {
|
|||
|
|
width: 100%;
|
|||
|
|
font-size: 40rpx;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #000000;
|
|||
|
|
padding: 0 20rpx;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
ttext-align: center;
|
|||
|
|
}
|
|||
|
|
.avatars {
|
|||
|
|
width: 100%;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: center;
|
|||
|
|
margin-top: 20rpx;
|
|||
|
|
.avatar-img {
|
|||
|
|
width: 150rpx;
|
|||
|
|
height: 150rpx;
|
|||
|
|
border-radius: 75rpx;
|
|||
|
|
border: 4rpx solid #ffffff;
|
|||
|
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
|||
|
|
// 添加点击效果
|
|||
|
|
&:active {
|
|||
|
|
opacity: 0.8;
|
|||
|
|
transform: scale(0.95);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.hello-text {
|
|||
|
|
width: 100%;
|
|||
|
|
text-align: center;
|
|||
|
|
margin-top: 20rpx;
|
|||
|
|
font-size: 30rpx;
|
|||
|
|
color: #000000;
|
|||
|
|
p {
|
|||
|
|
margin: 5rpx 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 数据统计区域样式 */
|
|||
|
|
.data-section {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 160rpx;
|
|||
|
|
background-color: #ffffff;
|
|||
|
|
margin-top: -30rpx;
|
|||
|
|
border-radius: 20rpx;
|
|||
|
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-around;
|
|||
|
|
padding: 0 40rpx;
|
|||
|
|
margin-bottom: 30rpx;
|
|||
|
|
.data-item {
|
|||
|
|
flex: 1;
|
|||
|
|
text-align: center;
|
|||
|
|
.data-number {
|
|||
|
|
font-size: 40rpx;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #333;
|
|||
|
|
display: block;
|
|||
|
|
margin-bottom: 10rpx;
|
|||
|
|
}
|
|||
|
|
.data-label {
|
|||
|
|
font-size: 24rpx;
|
|||
|
|
color: #666;
|
|||
|
|
}
|
|||
|
|
// 添加点击效果
|
|||
|
|
&:active {
|
|||
|
|
opacity: 0.7;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.data-divider {
|
|||
|
|
width: 1rpx;
|
|||
|
|
height: 80rpx;
|
|||
|
|
background-color: #eee;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 功能菜单区域样式 */
|
|||
|
|
.menu-section {
|
|||
|
|
width: 100%;
|
|||
|
|
padding: 0 20rpx;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
.menu-group {
|
|||
|
|
background-color: #ffffff;
|
|||
|
|
border-radius: 16rpx;
|
|||
|
|
margin-bottom: 30rpx;
|
|||
|
|
overflow: hidden;
|
|||
|
|
.menu-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
padding: 0 30rpx;
|
|||
|
|
height: 100rpx;
|
|||
|
|
border-bottom: 1rpx solid #f5f5f5;
|
|||
|
|
// 最后一个菜单项不需要底边框
|
|||
|
|
&:last-child {
|
|||
|
|
border-bottom: none;
|
|||
|
|
}
|
|||
|
|
.menu-left {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
.menu-icon {
|
|||
|
|
width: 40rpx;
|
|||
|
|
height: 40rpx;
|
|||
|
|
vertical-align: middle;
|
|||
|
|
}
|
|||
|
|
.menu-text {
|
|||
|
|
font-size: 32rpx;
|
|||
|
|
color: #333;
|
|||
|
|
margin-left: 20rpx;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.menu-right {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
.menu-badge {
|
|||
|
|
background-color: #FF3B30;
|
|||
|
|
color: #ffffff;
|
|||
|
|
font-size: 20rpx;
|
|||
|
|
padding: 2rpx 10rpx;
|
|||
|
|
border-radius: 10rpx;
|
|||
|
|
margin-right: 10rpx;
|
|||
|
|
min-width: 20rpx;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 添加点击效果
|
|||
|
|
&:active {
|
|||
|
|
background-color: #f8f8f8;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 退出登录按钮样式 */
|
|||
|
|
.logout-section {
|
|||
|
|
width: 100%;
|
|||
|
|
padding: 0 40rpx;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
margin-bottom: 40rpx;
|
|||
|
|
.logout-btn {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 90rpx;
|
|||
|
|
line-height: 90rpx;
|
|||
|
|
border-radius: 45rpx;
|
|||
|
|
font-size: 34rpx;
|
|||
|
|
background-color: #ffffff;
|
|||
|
|
color: #FF3B30;
|
|||
|
|
border: 1rpx solid #FF3B30;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 版本信息样式 */
|
|||
|
|
.version-info {
|
|||
|
|
width: 100%;
|
|||
|
|
text-align: center;
|
|||
|
|
padding-bottom: 60rpx;
|
|||
|
|
text {
|
|||
|
|
font-size: 24rpx;
|
|||
|
|
color: #999;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 安全区域适配 */
|
|||
|
|
/* #ifdef MP-WEIXIN */
|
|||
|
|
.my {
|
|||
|
|
padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
|
|||
|
|
}
|
|||
|
|
/* #endif */
|
|||
|
|
</style>
|