pet/pages/profile/profile.vue

923 lines
20 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="profile-container page-container-with-bg">
<!-- 用户信息卡片 -->
<view class="user-info-card">
<view class="user-avatar-section">
<view class="avatar-wrapper">
<u-avatar
:src="userInfo.avatarUrl || ''"
:text="userInfo.nickName ? userInfo.nickName.charAt(0) : '👤'"
size="100"
shape="circle"
bg-color="linear-gradient(135deg, #FF8A80, #FFB6C1)"
color="white"
font-size="40"
></u-avatar>
<view class="online-status" v-if="userInfo.nickName">
<view class="status-dot"></view>
</view>
</view>
</view>
<view class="user-info-section">
<view class="user-name">{{ userInfo.nickName || '点击登录' }}</view>
<view class="user-status">{{ userInfo.nickName ? '已登录' : '未登录' }}</view>
<view class="login-days" v-if="userInfo.nickName">已使用 {{ loginDays }} </view>
</view>
<view class="user-action" @click="handleUserAction">
<text class="action-icon">{{ userInfo.nickName ? '⚙️' : '👋' }}</text>
</view>
</view>
<!-- 宠物概览统计卡片 -->
<view class="stats-card">
<view class="stats-header">
<text class="stats-title">我的宠物</text>
<view class="stats-action" @click="navigateTo('/pages/pets/pets')">
<text class="action-text">管理</text>
<text class="action-arrow"></text>
</view>
</view>
<view class="stats-grid">
<view class="stat-item" @click="navigateTo('/pages/pets/pets')">
<view class="stat-number">{{ petStats.petCount }}</view>
<view class="stat-label">宠物</view>
<view class="stat-icon">🐱</view>
</view>
<view class="stat-item" @click="navigateTo('/pages/pets/pet-records')">
<view class="stat-number">{{ petStats.recordCount }}</view>
<view class="stat-label">记录</view>
<view class="stat-icon">📝</view>
</view>
<view class="stat-item" @click="showReminders">
<view class="stat-number">{{ petStats.reminderCount }}</view>
<view class="stat-label">提醒</view>
<view class="stat-icon"></view>
</view>
</view>
</view>
<!-- 家庭管理卡片 -->
<view class="family-card">
<view class="card-header">
<view class="header-left">
<text class="card-icon">👨👩👧👦</text>
<text class="card-title">我的家庭</text>
</view>
<view class="header-right" @click="navigateToFamily">
<text class="member-count">{{ familyStats.memberCount }}</text>
<text class="action-arrow"></text>
</view>
</view>
<view class="family-actions">
<view class="action-btn" @click="inviteFamily">
<text class="btn-icon"></text>
<text class="btn-text">邀请成员</text>
</view>
<view class="action-btn" @click="navigateToFamily">
<text class="btn-icon">👥</text>
<text class="btn-text">家庭设置</text>
</view>
</view>
</view>
<!-- 领养管理卡片 -->
<view class="adoption-card">
<view class="card-header">
<view class="header-left">
<text class="card-icon">🏠</text>
<text class="card-title">领养管理</text>
</view>
<view class="header-right" @click="navigateTo('/pages/adoption/my-adoption')">
<text class="action-arrow"></text>
</view>
</view>
<view class="adoption-stats">
<view class="adoption-item" @click="navigateTo('/pages/adoption/my-published')">
<view class="adoption-number">{{ adoptionStats.publishedCount }}</view>
<view class="adoption-label">已发布</view>
</view>
<view class="adoption-item" @click="navigateTo('/pages/adoption/my-applications')">
<view class="adoption-number">{{ adoptionStats.applicationCount }}</view>
<view class="adoption-label">已申请</view>
</view>
</view>
<view class="publish-btn" @click="navigateTo('/pages/adoption/publish')">
<text class="publish-icon">📝</text>
<text class="publish-text">发布领养信息</text>
</view>
</view>
<!-- 设置功能卡片 -->
<view class="settings-card">
<view class="settings-list">
<view class="setting-item" @click="navigateTo('/pages/profile/notifications')">
<view class="setting-left">
<text class="setting-icon">🔔</text>
<text class="setting-text">消息通知</text>
</view>
<view class="setting-right">
<text class="setting-badge" v-if="notificationCount > 0">{{ notificationCount }}</text>
<text class="setting-arrow">→</text>
</view>
</view>
<view class="setting-item" @click="navigateTo('/pages/profile/privacy')">
<view class="setting-left">
<text class="setting-icon">🔒</text>
<text class="setting-text">隐私设置</text>
</view>
<view class="setting-right">
<text class="setting-arrow">→</text>
</view>
</view>
<view class="setting-item" @click="navigateTo('/pages/profile/feedback')">
<view class="setting-left">
<text class="setting-icon">💬</text>
<text class="setting-text">意见反馈</text>
</view>
<view class="setting-right">
<text class="setting-arrow">→</text>
</view>
</view>
<view class="setting-item" @click="navigateTo('/pages/profile/about')">
<view class="setting-left">
<text class="setting-icon"></text>
<text class="setting-text">关于我们</text>
</view>
<view class="setting-right">
<text class="setting-arrow"></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { reactive, ref, onMounted, computed } from 'vue'
export default {
name: 'ProfilePage',
setup() {
// 响应式数据
const userInfo = ref({
nickName: '',
avatarUrl: ''
})
const loginDays = ref(0)
const notificationCount = ref(3)
// 宠物统计数据
const petStats = reactive({
petCount: 0,
recordCount: 0,
reminderCount: 0
})
// 家庭统计数据
const familyStats = reactive({
memberCount: 1
})
// 领养统计数据
const adoptionStats = reactive({
publishedCount: 0,
applicationCount: 0
})
// 方法定义
const initPage = () => {
checkLogin()
loadUserStats()
}
const checkLogin = () => {
// 检查是否已登录
const savedUserInfo = uni.getStorageSync('userInfo')
if (savedUserInfo) {
userInfo.value = savedUserInfo
calculateLoginDays()
}
}
const calculateLoginDays = () => {
const loginDate = uni.getStorageSync('loginDate')
if (loginDate) {
const now = new Date()
const login = new Date(loginDate)
const diffTime = Math.abs(now - login)
loginDays.value = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
}
}
const loadUserStats = () => {
try {
// 加载宠物统计数据
const pets = uni.getStorageSync('pets') || []
petStats.petCount = pets.length
// 加载记录统计数据 - 统计所有宠物的记录
let totalRecords = 0
pets.forEach(pet => {
const petRecords = uni.getStorageSync(`petRecords_${pet.id}`) || []
totalRecords += petRecords.length
})
petStats.recordCount = totalRecords
// 计算待处理提醒数量
const today = new Date()
const reminders = uni.getStorageSync('reminders') || []
const pendingReminders = reminders.filter(reminder => {
const reminderDate = new Date(reminder.date)
return reminderDate <= today && !reminder.completed
})
petStats.reminderCount = pendingReminders.length
// 加载家庭数据
const familyData = uni.getStorageSync('familyData') || { members: [] }
familyStats.memberCount = familyData.members.length || 1
// 加载领养数据
const adoptionData = uni.getStorageSync('adoptionData') || {
published: [],
applications: []
}
adoptionStats.publishedCount = adoptionData.published.length
adoptionStats.applicationCount = adoptionData.applications.length
// 加载通知数量
const notifications = uni.getStorageSync('notifications') || []
const unreadNotifications = notifications.filter(n => !n.read)
notificationCount.value = unreadNotifications.length
} catch (error) {
console.error('加载用户统计数据失败:', error)
// 设置默认值
petStats.petCount = 0
petStats.recordCount = 0
petStats.reminderCount = 0
familyStats.memberCount = 1
adoptionStats.publishedCount = 0
adoptionStats.applicationCount = 0
}
}
const handleUserAction = () => {
if (userInfo.value.nickName) {
// 已登录,跳转到个人信息设置
navigateTo('/pages/profile/user-info')
} else {
// 未登录,执行登录
wxLogin()
}
}
const wxLogin = () => {
uni.login({
provider: 'weixin',
success: (res) => {
console.log('登录成功', res)
// 模拟登录成功
userInfo.value = {
nickName: '宠物主人',
avatarUrl: ''
}
uni.setStorageSync('userInfo', userInfo.value)
uni.setStorageSync('loginDate', new Date().toISOString())
calculateLoginDays()
uni.showToast({
title: '登录成功',
icon: 'success'
})
},
fail: (err) => {
console.error('登录失败', err)
uni.showToast({
title: '登录失败',
icon: 'none'
})
}
})
}
const navigateTo = (url) => {
uni.navigateTo({
url,
fail: () => {
uni.showToast({
title: '页面开发中',
icon: 'none'
})
}
})
}
const navigateToFamily = () => {
navigateTo('/pages/profile/family')
}
const inviteFamily = () => {
uni.showModal({
title: '邀请家庭成员',
content: '通过微信分享邀请码邀请家人加入',
confirmText: '分享邀请',
success: (res) => {
if (res.confirm) {
uni.showToast({
title: '功能开发中',
icon: 'none'
})
}
}
})
}
const showReminders = () => {
if (petStats.reminderCount > 0) {
navigateTo('/pages/profile/reminders')
} else {
uni.showToast({
title: '暂无提醒事项',
icon: 'none'
})
}
}
// 刷新页面数据
const refreshData = () => {
loadUserStats()
}
// 页面显示时刷新数据
const onShow = () => {
refreshData()
}
// 下拉刷新
const onPullDownRefresh = () => {
refreshData()
setTimeout(() => {
uni.stopPullDownRefresh()
}, 1000)
}
// 格式化数字显示
const formatNumber = (num) => {
if (num >= 1000) {
return (num / 1000).toFixed(1) + 'k'
}
return num.toString()
}
// 检查是否有新功能提示
const checkNewFeatures = () => {
const lastVersion = uni.getStorageSync('lastAppVersion') || '1.0.0'
const currentVersion = '1.1.0' // 当前版本
if (lastVersion !== currentVersion) {
// 显示新功能提示
setTimeout(() => {
uni.showModal({
title: '发现新功能',
content: '新增了家庭共享和领养管理功能,快来体验吧!',
confirmText: '去看看',
success: (res) => {
if (res.confirm) {
uni.setStorageSync('lastAppVersion', currentVersion)
}
}
})
}, 2000)
}
}
// 初始化时检查新功能
onMounted(() => {
initPage()
checkNewFeatures()
})
return {
userInfo,
loginDays,
notificationCount,
petStats,
familyStats,
adoptionStats,
handleUserAction,
navigateTo,
navigateToFamily,
inviteFamily,
showReminders,
refreshData,
formatNumber,
onShow,
onPullDownRefresh
}
},
// 页面生命周期
onShow() {
this.onShow()
},
onPullDownRefresh() {
this.onPullDownRefresh()
}
}
</script>
<style lang="scss" scoped>
.profile-container {
padding-bottom: 40rpx;
}
/* 用户信息卡片 */
.user-info-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
margin: 0 30rpx 24rpx 30rpx;
border-radius: 24rpx;
padding: 32rpx;
display: flex;
align-items: center;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
}
.user-avatar-section {
.avatar-wrapper {
position: relative;
.online-status {
position: absolute;
bottom: 8rpx;
right: 8rpx;
width: 24rpx;
height: 24rpx;
background: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
.status-dot {
width: 16rpx;
height: 16rpx;
background: #4CAF50;
border-radius: 50%;
}
}
}
}
.user-info-section {
flex: 1;
margin-left: 24rpx;
.user-name {
font-size: 36rpx;
font-weight: 600;
color: #333333;
margin-bottom: 8rpx;
}
.user-status {
font-size: 24rpx;
color: #FF8A80;
margin-bottom: 4rpx;
}
.login-days {
font-size: 22rpx;
color: #999999;
}
}
.user-action {
.action-icon {
font-size: 32rpx;
}
}
}
/* 宠物概览统计卡片 */
.stats-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
margin: 0 30rpx 24rpx 30rpx;
border-radius: 24rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.stats-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.stats-title {
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
.stats-action {
display: flex;
align-items: center;
.action-text {
font-size: 24rpx;
color: #FF8A80;
margin-right: 8rpx;
}
.action-arrow {
font-size: 24rpx;
color: #FF8A80;
}
}
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 24rpx;
.stat-item {
text-align: center;
padding: 24rpx 16rpx;
border-radius: 16rpx;
background: rgba(255, 138, 128, 0.05);
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background: rgba(255, 138, 128, 0.1);
}
.stat-number {
font-size: 40rpx;
font-weight: 700;
color: #FF8A80;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 22rpx;
color: #666666;
margin-bottom: 8rpx;
}
.stat-icon {
font-size: 28rpx;
}
}
}
}
/* 家庭管理卡片 */
.family-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
margin: 0 30rpx 24rpx 30rpx;
border-radius: 24rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.header-left {
display: flex;
align-items: center;
.card-icon {
font-size: 32rpx;
margin-right: 12rpx;
}
.card-title {
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
}
.header-right {
display: flex;
align-items: center;
.member-count {
font-size: 24rpx;
color: #FF8A80;
margin-right: 8rpx;
}
.action-arrow {
font-size: 24rpx;
color: #FF8A80;
}
}
}
.family-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16rpx;
.action-btn {
display: flex;
flex-direction: column;
align-items: center;
padding: 24rpx 16rpx;
border-radius: 16rpx;
background: rgba(255, 138, 128, 0.05);
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background: rgba(255, 138, 128, 0.1);
}
.btn-icon {
font-size: 32rpx;
margin-bottom: 8rpx;
}
.btn-text {
font-size: 22rpx;
color: #666666;
}
}
}
}
/* 领养管理卡片 */
.adoption-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
margin: 0 30rpx 24rpx 30rpx;
border-radius: 24rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.header-left {
display: flex;
align-items: center;
.card-icon {
font-size: 32rpx;
margin-right: 12rpx;
}
.card-title {
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
}
.header-right {
.action-arrow {
font-size: 24rpx;
color: #FF8A80;
}
}
}
.adoption-stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16rpx;
margin-bottom: 24rpx;
.adoption-item {
text-align: center;
padding: 20rpx 16rpx;
border-radius: 16rpx;
background: rgba(255, 138, 128, 0.05);
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background: rgba(255, 138, 128, 0.1);
}
.adoption-number {
font-size: 36rpx;
font-weight: 700;
color: #FF8A80;
margin-bottom: 8rpx;
}
.adoption-label {
font-size: 22rpx;
color: #666666;
}
}
}
.publish-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx;
border-radius: 16rpx;
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
}
.publish-icon {
font-size: 24rpx;
margin-right: 8rpx;
}
.publish-text {
font-size: 26rpx;
color: white;
font-weight: 500;
}
}
}
/* 设置功能卡片 */
.settings-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
margin: 0 30rpx 24rpx 30rpx;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
overflow: hidden;
.settings-list {
.setting-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
&:last-child {
border-bottom: none;
}
&:active {
background: rgba(255, 138, 128, 0.05);
}
.setting-left {
display: flex;
align-items: center;
.setting-icon {
font-size: 32rpx;
margin-right: 16rpx;
}
.setting-text {
font-size: 30rpx;
color: #333333;
font-weight: 500;
}
}
.setting-right {
display: flex;
align-items: center;
.setting-badge {
background: #FF8A80;
color: white;
font-size: 20rpx;
padding: 4rpx 12rpx;
border-radius: 20rpx;
margin-right: 12rpx;
min-width: 32rpx;
text-align: center;
}
.setting-arrow {
font-size: 24rpx;
color: #FF8A80;
}
}
}
}
}
/* 响应式设计 */
@media (max-width: 375px) {
.profile-container {
.user-info-card {
margin: 0 20rpx 20rpx 20rpx;
padding: 24rpx;
}
.stats-card,
.family-card,
.adoption-card,
.settings-card {
margin: 0 20rpx 20rpx 20rpx;
padding: 24rpx;
}
.stats-grid {
gap: 16rpx;
.stat-item {
padding: 20rpx 12rpx;
.stat-number {
font-size: 36rpx;
}
}
}
.family-actions {
gap: 12rpx;
.action-btn {
padding: 20rpx 12rpx;
}
}
}
}
/* 加载状态 */
.loading-state {
display: flex;
justify-content: center;
align-items: center;
padding: 60rpx;
.loading-text {
font-size: 24rpx;
color: #999999;
margin-left: 16rpx;
}
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 60rpx 40rpx;
.empty-icon {
font-size: 80rpx;
margin-bottom: 16rpx;
opacity: 0.5;
}
.empty-text {
font-size: 24rpx;
color: #999999;
line-height: 1.5;
}
}
/* 动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.profile-container > view {
animation: fadeIn 0.5s ease-out;
}
.profile-container > view:nth-child(1) { animation-delay: 0.1s; }
.profile-container > view:nth-child(2) { animation-delay: 0.2s; }
.profile-container > view:nth-child(3) { animation-delay: 0.3s; }
.profile-container > view:nth-child(4) { animation-delay: 0.4s; }
.profile-container > view:nth-child(5) { animation-delay: 0.5s; }
</style>