Files
msh-system/msh_single_uniapp/pages/tool/my-profile.vue

616 lines
14 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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="my-profile-page">
<!-- 用户信息 -->
<view class="profile-header">
<view class="user-info-section">
<view class="user-avatar">
<text class="avatar-icon">👤</text>
</view>
<view class="user-details">
<view class="user-name-row">
<text class="user-name">{{ userInfo.name }}</text>
<view class="verified-badge">
<image class="verified-icon" :src="iconVerified" mode="aspectFit"></image>
</view>
</view>
<view class="user-tags">
<view class="user-tag">{{ userInfo.stage }}</view>
<text class="user-id">ID: {{ userInfo.id }}</text>
</view>
</view>
</view>
</view>
<!-- 内容区域 -->
<scroll-view class="content-scroll" scroll-y>
<!-- 统计数据卡片 -->
<view class="stats-card">
<view class="stat-item" @click="goToCheckin">
<text class="stat-value">{{ stats.checkin }}</text>
<text class="stat-label">打卡</text>
</view>
<view class="stat-item" @click="goToPoints">
<text class="stat-value">{{ stats.points }}</text>
<text class="stat-label">积分</text>
</view>
<view class="stat-item" @click="goToFollowing">
<text class="stat-value">{{ stats.following }}</text>
<text class="stat-label">关注</text>
</view>
</view>
<!-- 我的健康 -->
<view class="section-card">
<view class="section-title">我的健康</view>
<view class="menu-list">
<view class="menu-item" @click="goToHealthRecord">
<text class="menu-icon">🏥</text>
<text class="menu-text">健康档案</text>
</view>
<view class="menu-item" @click="goToDietRecord">
<text class="menu-icon">📊</text>
<text class="menu-text">饮食记录</text>
<view class="menu-badge">{{ dietRecordCount }}</view>
</view>
</view>
</view>
<!-- 我的内容 -->
<view class="section-card">
<view class="section-title">我的内容</view>
<view class="menu-list">
<view class="menu-item" @click="goToMyLikes">
<image class="menu-icon-img" :src="iconLike" mode="aspectFit"></image>
<text class="menu-text">我的点赞</text>
<view class="menu-badge">{{ myLikesCount }}</view>
</view>
<view class="menu-item" @click="goToMyCollections">
<image class="menu-icon-img" :src="iconCollection" mode="aspectFit"></image>
<text class="menu-text">我的收藏</text>
<view class="menu-badge">{{ myCollectionsCount }}</view>
</view>
<view class="menu-item" @click="goToMyRecipes">
<text class="menu-icon">📝</text>
<text class="menu-text">我的食谱</text>
<view class="menu-badge">{{ myRecipesCount }}</view>
</view>
</view>
</view>
<!-- 工具与服务 -->
<view class="section-card">
<view class="section-title">工具与服务</view>
<view class="menu-list">
<view class="menu-item" @click="goToNutritionist">
<text class="menu-icon">👨</text>
<text class="menu-text">我的营养师</text>
<view class="menu-badge online">在线</view>
</view>
<view class="menu-item" @click="goToInvite">
<image class="menu-icon-img" :src="iconGift" mode="aspectFit"></image>
<text class="menu-text">邀请有礼</text>
</view>
<view class="menu-item" @click="goToNotifications">
<image class="menu-icon-img" :src="iconNotification" mode="aspectFit"></image>
<text class="menu-text">消息通知</text>
<view class="menu-badge">{{ notificationCount }}</view>
</view>
<view class="menu-item" @click="goToNutritionGuide">
<text class="menu-icon">🥗</text>
<text class="menu-text">营养指导</text>
</view>
<view class="menu-item" @click="goToMedicationGuide">
<text class="menu-icon">💊</text>
<text class="menu-text">用药指导</text>
</view>
</view>
</view>
<!-- 设置 -->
<view class="section-card">
<view class="section-title">设置</view>
<view class="menu-list">
<view class="menu-item" @click="goToAccountSettings">
<image class="menu-icon-img" :src="iconSettings" mode="aspectFit"></image>
<text class="menu-text">账号设置</text>
</view>
<view class="menu-item" @click="goToPrivacySettings">
<image class="menu-icon-img" :src="iconPrivacy" mode="aspectFit"></image>
<text class="menu-text">隐私设置</text>
</view>
<view class="menu-item" @click="goToHelp">
<image class="menu-icon-img" :src="iconHelp" mode="aspectFit"></image>
<text class="menu-text">帮助与反馈</text>
</view>
<view class="menu-item" @click="goToAbout">
<text class="menu-icon"></text>
<text class="menu-text">关于我们</text>
<text class="version-text">v2.0</text>
</view>
</view>
</view>
<!-- 退出登录按钮 -->
<view class="logout-btn" @click="handleLogout">
<image class="logout-icon" :src="iconLogout" mode="aspectFit"></image>
<text>退出登录</text>
</view>
<!-- 底部安全距离 -->
<view class="safe-bottom"></view>
</scroll-view>
</view>
</template>
<script>
import { getUserPoints, getCheckinStreak } from '@/api/tool.js';
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({ storeUserInfo: 'userInfo', uid: 'uid', isLogin: 'isLogin' })
},
data() {
return {
iconVerified: 'https://www.figma.com/api/mcp/asset/e06ebfe5-bf8d-40e7-9b5f-a395c823127b',
iconLike: 'https://www.figma.com/api/mcp/asset/dd7b88ff-b674-48b4-80f9-059f6205709e',
iconCollection: 'https://www.figma.com/api/mcp/asset/3e07edd4-5f53-4d38-8de9-ef920713385f',
iconGift: 'https://www.figma.com/api/mcp/asset/afaeb0a1-7276-4a8c-87c0-ba4dc4ce3eba',
iconNotification: 'https://www.figma.com/api/mcp/asset/5b415d37-7e7d-4069-b714-cc8dad364bb4',
iconSettings: 'https://www.figma.com/api/mcp/asset/a6107d1c-4643-4a9c-aa57-2f90ba8c125c',
iconPrivacy: 'https://www.figma.com/api/mcp/asset/e72b9b89-6013-4c6f-b19f-95b9042f03bb',
iconHelp: 'https://www.figma.com/api/mcp/asset/1d05ae21-1147-4e48-83ac-3357447cc199',
iconLogout: 'https://www.figma.com/api/mcp/asset/a4d5597f-0287-4411-a173-1e62db3c6c9f',
userInfo: {
name: '慢友小张',
stage: '透析期',
id: '1001'
},
stats: {
checkin: 0,
points: 0,
following: 0
},
dietRecordCount: 0,
myLikesCount: 0,
myCollectionsCount: 0,
myRecipesCount: 0,
notificationCount: 0
}
},
onLoad() {
this.syncUserInfo();
this.loadProfileStats();
},
onShow() {
this.syncUserInfo();
this.loadProfileStats();
},
methods: {
syncUserInfo() {
if (this.isLogin && this.storeUserInfo) {
this.userInfo = {
name: this.storeUserInfo.nickname || '慢友小张',
stage: this.storeUserInfo.level || '透析期',
id: this.uid || '1001'
}
}
},
async loadProfileStats() {
try {
const [pointsRes, streakRes] = await Promise.all([
getUserPoints().catch(() => ({ data: {} })),
getCheckinStreak().catch(() => ({ data: {} }))
]);
const pointsData = pointsRes.data || {};
const streakData = streakRes.data || {};
this.stats = {
checkin: streakData.totalCheckins || streakData.currentStreak || this.stats.checkin,
points: pointsData.points || pointsData.totalPoints || this.stats.points,
following: pointsData.followingCount || this.stats.following
};
this.dietRecordCount = streakData.totalCheckins || this.dietRecordCount;
} catch (error) {
console.error('加载个人统计失败:', error);
}
},
goToCheckin() {
uni.navigateTo({
url: '/pages/tool/checkin'
})
},
goToPoints() {
uni.navigateTo({
url: '/pages/tool/points-rules'
})
},
goToFollowing() {
uni.showToast({
title: '关注页面开发中',
icon: 'none'
})
},
goToHealthRecord() {
uni.showToast({
title: '健康档案功能开发中',
icon: 'none'
})
},
goToDietRecord() {
uni.navigateTo({
url: '/pages/tool/dietary-records'
})
},
goToMyLikes() {
uni.showToast({
title: '我的点赞功能开发中',
icon: 'none'
})
},
goToMyCollections() {
uni.showToast({
title: '我的收藏功能开发中',
icon: 'none'
})
},
goToMyRecipes() {
uni.showToast({
title: '我的食谱功能开发中',
icon: 'none'
})
},
goToNutritionist() {
uni.showToast({
title: '我的营养师功能开发中',
icon: 'none'
})
},
goToInvite() {
uni.navigateTo({
url: '/pages/tool/invite-rewards'
})
},
goToNotifications() {
uni.showToast({
title: '消息通知功能开发中',
icon: 'none'
})
},
goToNutritionGuide() {
uni.showToast({
title: '营养指导功能开发中',
icon: 'none'
})
},
goToMedicationGuide() {
uni.showToast({
title: '用药指导功能开发中',
icon: 'none'
})
},
goToAccountSettings() {
uni.showToast({
title: '账号设置功能开发中',
icon: 'none'
})
},
goToPrivacySettings() {
uni.showToast({
title: '隐私设置功能开发中',
icon: 'none'
})
},
goToHelp() {
uni.showToast({
title: '帮助与反馈功能开发中',
icon: 'none'
})
},
goToAbout() {
uni.showToast({
title: '关于我们功能开发中',
icon: 'none'
})
},
handleLogout() {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 清除本地存储的登录信息
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
uni.removeStorageSync('uid')
uni.removeStorageSync('expires_time')
// 清除 Vuex 状态
this.$store.commit('LOGOUT')
uni.showToast({
title: '退出登录成功',
icon: 'success'
})
// 跳转到登录页或首页
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
}, 1500)
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.my-profile-page {
min-height: 100vh;
background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);
display: flex;
flex-direction: column;
}
/* 顶部导航栏和用户信息 */
.profile-header {
background: linear-gradient(135deg, #ff8c52 0%, #ff7f50 50%, #ff6b35 100%);
padding-top: 0;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
right: -80rpx;
top: -80rpx;
width: 384rpx;
height: 384rpx;
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
filter: blur(60rpx);
}
&::after {
content: '';
position: absolute;
left: -80rpx;
bottom: -80rpx;
width: 320rpx;
height: 320rpx;
background: rgba(0, 0, 0, 0.05);
border-radius: 50%;
filter: blur(40rpx);
}
}
.user-info-section {
display: flex;
align-items: center;
gap: 1rpx;
padding: calc(var(--status-bar-height, 0) + 1rpx) 32rpx 32rpx;
position: relative;
z-index: 1;
}
.user-avatar {
width: 128rpx;
height: 128rpx; margin-right: 24rpx;
background: #ffffff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 40rpx 50rpx rgba(0, 0, 0, 0.1), 0 16rpx 20rpx rgba(0, 0, 0, 0.1);
.avatar-icon {
font-size: 60rpx;
}
}
.user-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 20rpx;
}
.user-name-row {
display: flex;
align-items: center;
gap: 16rpx;
.user-name {
font-size: 36rpx;
color: #ffffff;
font-weight: 500;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
}
.verified-badge {
width: 32rpx;
height: 32rpx;
background: #ff6b35;
border: 2rpx solid #ffffff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
.verified-icon {
width: 20rpx;
height: 20rpx;
}
}
}
.user-tags {
display: flex;
align-items: center;
gap: 16rpx;
.user-tag {
background: rgba(255, 255, 255, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
border-radius: 50rpx;
padding: 4rpx 20rpx;
font-size: 24rpx;
color: #ffffff;
}
.user-id {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.8);
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
}
/* 内容滚动区域 */
.content-scroll {
flex: 1;
padding: 0;
}
/* 统计数据卡片 */
.stats-card {
background: #ffffff;
border-radius: 32rpx;
padding: 20rpx;
margin: 32rpx 32rpx 0;
display: flex;
justify-content: space-around;
box-shadow: 0 20rpx 30rpx rgba(0, 0, 0, 0.1), 0 8rpx 12rpx rgba(0, 0, 0, 0.1);
}
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
flex: 1;
.stat-value {
font-size: 40rpx;
color: #1e2939;
font-weight: 500;
}
.stat-label {
font-size: 24rpx;
color: #6a7282;
}
}
/* 通用卡片样式 */
.section-card {
background: #ffffff;
border: 1rpx solid #e8eaed;
border-radius: 24rpx;
margin: 32rpx;
padding: 24rpx;
}
.section-title {
font-size: 28rpx;
color: #9fa5c0;
margin-bottom: 16rpx;
padding-left: 16rpx;
}
.menu-list {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.menu-item {
display: flex;
align-items: center;
gap: 24rpx;
padding: 8rpx 16rpx;
border-radius: 16rpx;
min-height: 80rpx;
transition: background-color 0.2s;
&:active {
background: #f8f9fa;
}
}
.menu-icon {
font-size: 40rpx;
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.menu-icon-img {
width: 40rpx;
height: 40rpx;
flex-shrink: 0;
}
.menu-text {
flex: 1;
font-size: 28rpx;
color: #2e3e5c;
}
.menu-badge {
background: linear-gradient(180deg, #fff5f0 0%, #ffe8dc 100%);
border: 1rpx solid rgba(255, 107, 53, 0.3);
border-radius: 50rpx;
padding: 4rpx 16rpx;
font-size: 24rpx;
color: #ff6b35;
flex-shrink: 0;
&.online {
background: linear-gradient(180deg, #fff5f0 0%, #ffe8dc 100%);
border: 1rpx solid rgba(255, 107, 53, 0.3);
color: #ff6b35;
}
}
.version-text {
font-size: 24rpx;
color: #9fa5c0;
flex-shrink: 0;
}
/* 退出登录按钮 */
.logout-btn {
background: #ffffff;
border-radius: 24rpx;
height: 96rpx;
margin: 0 32rpx 32rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1);
.logout-icon {
width: 40rpx;
height: 40rpx;
}
text {
font-size: 32rpx;
color: #364153;
font-weight: 500;
}
}
/* 底部安全距离 */
.safe-bottom {
height: 40rpx;
}
</style>