Initial commit: MSH System\n\n- msh_single_uniapp: Vue 2 + UniApp 前端(微信小程序/H5/App/支付宝小程序)\n- msh_crmeb_22: Spring Boot 2.2 后端(C端API/管理端/业务逻辑)\n- models-integration: AI服务集成(Coze/KieAI/腾讯ASR)\n- docs: 产品文档与设计稿
This commit is contained in:
615
msh_single_uniapp/pages/tool/my-profile.vue
Normal file
615
msh_single_uniapp/pages/tool/my-profile.vue
Normal file
@@ -0,0 +1,615 @@
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user