662 lines
14 KiB
Vue
662 lines
14 KiB
Vue
<template>
|
|
<view class="pets-container">
|
|
<!-- 顶部信息栏 -->
|
|
<view class="top-info-bar">
|
|
<view class="info-content">
|
|
<view class="welcome-text">
|
|
<text class="main-title">🐾 我的宠物</text>
|
|
<text class="sub-title">{{ petsList.length }}只小可爱陪伴着你</text>
|
|
</view>
|
|
<view class="top-actions">
|
|
<view class="action-btn" @click="showQuickActions = true">
|
|
<u-icon name="apps" color="#FF8A80" size="20"></u-icon>
|
|
</view>
|
|
<view class="action-btn add-btn" @click="addPet">
|
|
<u-icon name="plus" color="#ffffff" size="18"></u-icon>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 统计卡片 -->
|
|
<view class="stats-card" v-if="petsList.length > 0">
|
|
<view class="stats-item">
|
|
<view class="stats-number">{{ totalRecords }}</view>
|
|
<view class="stats-label">记录</view>
|
|
</view>
|
|
<view class="stats-item">
|
|
<view class="stats-number">{{ totalDays }}</view>
|
|
<view class="stats-label">陪伴天数</view>
|
|
</view>
|
|
<view class="stats-item">
|
|
<view class="stats-number">{{ upcomingReminders }}</view>
|
|
<view class="stats-label">待办提醒</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 宠物列表 -->
|
|
<view class="pets-list" v-if="petsList.length > 0">
|
|
<view class="pet-card" v-for="pet in petsList" :key="pet.id" @click="viewPetDetail(pet)">
|
|
<!-- 宠物头像和基本信息 -->
|
|
<view class="pet-header">
|
|
<view class="pet-avatar-container">
|
|
<u-avatar :src="pet.avatar || '/static/default-pet.png'" size="70" shape="circle"></u-avatar>
|
|
<view class="pet-status" :class="pet.healthStatus || 'healthy'">
|
|
<u-icon :name="getHealthIcon(pet.healthStatus)" size="12" color="#ffffff"></u-icon>
|
|
</view>
|
|
</view>
|
|
<view class="pet-basic-info">
|
|
<view class="pet-name-row">
|
|
<text class="pet-name">{{ pet.name }}</text>
|
|
<view class="pet-gender" :class="pet.gender === '公' ? 'male' : 'female'">
|
|
<u-icon :name="pet.gender === '公' ? 'man' : 'woman'" size="12" color="#ffffff"></u-icon>
|
|
</view>
|
|
</view>
|
|
<text class="pet-breed">{{ pet.breed }}</text>
|
|
<text class="pet-age">{{ pet.age }}岁 · 陪伴{{ pet.companionDays }}天</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 宠物特征标签 -->
|
|
<view class="pet-tags" v-if="pet.personality && pet.personality.length > 0">
|
|
<u-tag
|
|
v-for="tag in pet.personality.slice(0, 3)"
|
|
:key="tag"
|
|
:text="tag"
|
|
type="primary"
|
|
size="mini"
|
|
plain
|
|
></u-tag>
|
|
</view>
|
|
|
|
<!-- 快捷操作按钮 -->
|
|
<view class="pet-actions">
|
|
<view class="action-item" @click.stop="addRecord(pet)">
|
|
<u-icon name="edit-pen" size="16" color="#81C784"></u-icon>
|
|
<text class="action-text">记录</text>
|
|
</view>
|
|
<view class="action-item" @click.stop="chatWithPet(pet)">
|
|
<u-icon name="chat" size="16" color="#64B5F6"></u-icon>
|
|
<text class="action-text">聊天</text>
|
|
</view>
|
|
<view class="action-item" @click.stop="viewHealth(pet)">
|
|
<u-icon name="heart" size="16" color="#FF8A80"></u-icon>
|
|
<text class="action-text">健康</text>
|
|
</view>
|
|
<view class="action-item" @click.stop="viewTimeline(pet)">
|
|
<u-icon name="clock" size="16" color="#FFB74D"></u-icon>
|
|
<text class="action-text">时光</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view class="empty-state" v-else>
|
|
<image class="empty-image" src="/static/empty-pets.png" mode="aspectFit"></image>
|
|
<text class="empty-title">还没有小伙伴呢</text>
|
|
<text class="empty-desc">添加你的第一只宠物,开始记录美好时光吧~</text>
|
|
<u-button
|
|
class="add-first-pet-btn"
|
|
type="primary"
|
|
text="添加第一只宠物"
|
|
shape="round"
|
|
@click="addPet"
|
|
></u-button>
|
|
</view>
|
|
|
|
<!-- 快捷操作弹窗 -->
|
|
<u-popup v-model="showQuickActions" mode="bottom" border-radius="20">
|
|
<view class="quick-actions-popup">
|
|
<view class="popup-header">
|
|
<text class="popup-title">快捷操作</text>
|
|
<u-icon name="close" size="20" @click="showQuickActions = false"></u-icon>
|
|
</view>
|
|
<view class="quick-actions-grid">
|
|
<view class="quick-action-item" @click="navigateToRecords">
|
|
<u-icon name="list" size="24" color="#81C784"></u-icon>
|
|
<text class="quick-action-text">所有记录</text>
|
|
</view>
|
|
<view class="quick-action-item" @click="navigateToStats">
|
|
<u-icon name="bar-chart" size="24" color="#64B5F6"></u-icon>
|
|
<text class="quick-action-text">数据统计</text>
|
|
</view>
|
|
<view class="quick-action-item" @click="navigateToReminders">
|
|
<u-icon name="bell" size="24" color="#FFB74D"></u-icon>
|
|
<text class="quick-action-text">提醒事项</text>
|
|
</view>
|
|
<view class="quick-action-item" @click="exportData">
|
|
<u-icon name="share" size="24" color="#FF8A80"></u-icon>
|
|
<text class="quick-action-text">数据导出</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</u-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
petsList: [],
|
|
showQuickActions: false,
|
|
totalRecords: 0,
|
|
totalDays: 0,
|
|
upcomingReminders: 0
|
|
}
|
|
},
|
|
onShow() {
|
|
this.loadPets()
|
|
this.loadStatistics()
|
|
},
|
|
computed: {
|
|
// 计算总陪伴天数
|
|
totalCompanionDays() {
|
|
return this.petsList.reduce((total, pet) => total + (pet.companionDays || 0), 0)
|
|
}
|
|
},
|
|
methods: {
|
|
loadPets() {
|
|
try {
|
|
let pets = uni.getStorageSync('pets') || []
|
|
|
|
// 如果没有宠物数据,添加一些模拟数据
|
|
if (pets.length === 0) {
|
|
pets = [
|
|
{
|
|
id: 1,
|
|
name: '小橘',
|
|
breed: '橘猫',
|
|
age: 2,
|
|
companionDays: 365,
|
|
avatar: '/static/default-pet.png',
|
|
gender: '公',
|
|
weight: '4.5kg',
|
|
birthday: '2022-01-15',
|
|
healthStatus: 'healthy',
|
|
personality: ['活泼', '粘人', '贪吃'],
|
|
lastRecord: '2024-01-15'
|
|
},
|
|
{
|
|
id: 2,
|
|
name: '小白',
|
|
breed: '金毛',
|
|
age: 3,
|
|
companionDays: 1095,
|
|
avatar: '/static/default-pet.png',
|
|
gender: '母',
|
|
weight: '25kg',
|
|
birthday: '2021-03-20',
|
|
healthStatus: 'healthy',
|
|
personality: ['温顺', '聪明', '忠诚'],
|
|
lastRecord: '2024-01-14'
|
|
}
|
|
]
|
|
// 保存模拟数据到本地存储
|
|
uni.setStorageSync('pets', pets)
|
|
}
|
|
|
|
this.petsList = pets
|
|
} catch (error) {
|
|
console.error('加载宠物列表失败', error)
|
|
this.petsList = []
|
|
}
|
|
},
|
|
|
|
loadStatistics() {
|
|
try {
|
|
// 加载统计数据
|
|
const records = uni.getStorageSync('petRecords') || []
|
|
this.totalRecords = records.length
|
|
|
|
// 计算总陪伴天数
|
|
this.totalDays = this.petsList.reduce((total, pet) => total + (pet.companionDays || 0), 0)
|
|
|
|
// 模拟待办提醒数量
|
|
this.upcomingReminders = Math.floor(Math.random() * 5) + 1
|
|
} catch (error) {
|
|
console.error('加载统计数据失败', error)
|
|
}
|
|
},
|
|
|
|
getHealthIcon(status) {
|
|
const iconMap = {
|
|
healthy: 'checkmark',
|
|
warning: 'warning',
|
|
sick: 'close'
|
|
}
|
|
return iconMap[status] || 'checkmark'
|
|
},
|
|
|
|
addPet() {
|
|
uni.navigateTo({
|
|
url: '/pages/pets/add-pet'
|
|
})
|
|
},
|
|
|
|
viewPetDetail(pet) {
|
|
uni.navigateTo({
|
|
url: `/pages/pets/pet-detail?id=${pet.id}`
|
|
})
|
|
},
|
|
|
|
chatWithPet(pet) {
|
|
uni.navigateTo({
|
|
url: `/pages/pets/pet-chat-simple?petId=${pet.id}`
|
|
})
|
|
},
|
|
|
|
addRecord(pet) {
|
|
uni.navigateTo({
|
|
url: `/pages/pets/add-record-simple?petId=${pet.id}`
|
|
})
|
|
},
|
|
|
|
viewHealth(pet) {
|
|
uni.navigateTo({
|
|
url: `/pages/pets/health-charts?petId=${pet.id}`
|
|
})
|
|
},
|
|
|
|
viewTimeline(pet) {
|
|
uni.navigateTo({
|
|
url: `/pages/pets/pet-timeline?petId=${pet.id}`
|
|
})
|
|
},
|
|
|
|
// 快捷操作方法
|
|
navigateToRecords() {
|
|
this.showQuickActions = false
|
|
uni.navigateTo({
|
|
url: '/pages/pets/all-records'
|
|
})
|
|
},
|
|
|
|
navigateToStats() {
|
|
this.showQuickActions = false
|
|
uni.navigateTo({
|
|
url: '/pages/pets/statistics'
|
|
})
|
|
},
|
|
|
|
navigateToReminders() {
|
|
this.showQuickActions = false
|
|
uni.navigateTo({
|
|
url: '/pages/pets/reminders'
|
|
})
|
|
},
|
|
|
|
exportData() {
|
|
this.showQuickActions = false
|
|
uni.showToast({
|
|
title: '数据导出功能开发中',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.pets-container {
|
|
background: linear-gradient(135deg, #FFF8F0 0%, #F8F9FA 100%);
|
|
min-height: 100vh;
|
|
padding-bottom: 20rpx;
|
|
}
|
|
|
|
/* 顶部信息栏 */
|
|
.top-info-bar {
|
|
background: linear-gradient(135deg, #FF8A80 0%, #FFB74D 100%);
|
|
padding: 30rpx;
|
|
border-radius: 0 0 40rpx 40rpx;
|
|
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.3);
|
|
|
|
.info-content {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.welcome-text {
|
|
.main-title {
|
|
color: #ffffff;
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
display: block;
|
|
}
|
|
|
|
.sub-title {
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-size: 24rpx;
|
|
margin-top: 8rpx;
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
.top-actions {
|
|
display: flex;
|
|
gap: 20rpx;
|
|
align-items: center;
|
|
}
|
|
|
|
.action-btn {
|
|
width: 72rpx;
|
|
height: 72rpx;
|
|
border-radius: 36rpx;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
backdrop-filter: blur(10rpx);
|
|
|
|
&.add-btn {
|
|
background: rgba(255, 255, 255, 0.3);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 统计卡片 */
|
|
.stats-card {
|
|
background: #ffffff;
|
|
margin: 30rpx;
|
|
padding: 40rpx;
|
|
border-radius: 24rpx;
|
|
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08);
|
|
display: flex;
|
|
justify-content: space-around;
|
|
|
|
.stats-item {
|
|
text-align: center;
|
|
|
|
.stats-number {
|
|
font-size: 48rpx;
|
|
font-weight: bold;
|
|
color: #FF8A80;
|
|
line-height: 1;
|
|
}
|
|
|
|
.stats-label {
|
|
font-size: 24rpx;
|
|
color: #999999;
|
|
margin-top: 8rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 宠物列表 */
|
|
.pets-list {
|
|
padding: 0 30rpx;
|
|
}
|
|
|
|
.pet-card {
|
|
background: #ffffff;
|
|
border-radius: 24rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 30rpx;
|
|
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08);
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 8rpx;
|
|
background: linear-gradient(90deg, #FF8A80, #81C784, #64B5F6);
|
|
}
|
|
|
|
.pet-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.pet-avatar-container {
|
|
position: relative;
|
|
margin-right: 24rpx;
|
|
|
|
.pet-status {
|
|
position: absolute;
|
|
bottom: -4rpx;
|
|
right: -4rpx;
|
|
width: 32rpx;
|
|
height: 32rpx;
|
|
border-radius: 16rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 4rpx solid #ffffff;
|
|
|
|
&.healthy {
|
|
background: #81C784;
|
|
}
|
|
|
|
&.warning {
|
|
background: #FFB74D;
|
|
}
|
|
|
|
&.sick {
|
|
background: #FF8A80;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pet-basic-info {
|
|
flex: 1;
|
|
|
|
.pet-name-row {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.pet-name {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
margin-right: 16rpx;
|
|
}
|
|
|
|
.pet-gender {
|
|
width: 32rpx;
|
|
height: 32rpx;
|
|
border-radius: 16rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
&.male {
|
|
background: #64B5F6;
|
|
}
|
|
|
|
&.female {
|
|
background: #F06292;
|
|
}
|
|
}
|
|
|
|
.pet-breed {
|
|
font-size: 28rpx;
|
|
color: #666666;
|
|
margin-bottom: 8rpx;
|
|
display: block;
|
|
}
|
|
|
|
.pet-age {
|
|
font-size: 24rpx;
|
|
color: #999999;
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
.pet-tags {
|
|
margin-bottom: 24rpx;
|
|
display: flex;
|
|
gap: 16rpx;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.pet-actions {
|
|
display: flex;
|
|
justify-content: space-around;
|
|
padding-top: 24rpx;
|
|
border-top: 2rpx solid #F5F5F5;
|
|
|
|
.action-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 8rpx;
|
|
padding: 16rpx;
|
|
border-radius: 16rpx;
|
|
transition: all 0.3s ease;
|
|
|
|
&:active {
|
|
background: #F5F5F5;
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
.action-text {
|
|
font-size: 22rpx;
|
|
color: #666666;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 空状态 */
|
|
.empty-state {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 120rpx 60rpx;
|
|
text-align: center;
|
|
|
|
.empty-image {
|
|
width: 300rpx;
|
|
height: 300rpx;
|
|
margin-bottom: 40rpx;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.empty-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.empty-desc {
|
|
font-size: 28rpx;
|
|
color: #999999;
|
|
line-height: 1.5;
|
|
margin-bottom: 60rpx;
|
|
}
|
|
|
|
.add-first-pet-btn {
|
|
width: 400rpx;
|
|
height: 88rpx;
|
|
background: linear-gradient(135deg, #FF8A80, #FFB74D);
|
|
border: none;
|
|
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.4);
|
|
}
|
|
}
|
|
|
|
/* 快捷操作弹窗 */
|
|
.quick-actions-popup {
|
|
background: #ffffff;
|
|
border-radius: 20rpx 20rpx 0 0;
|
|
padding: 40rpx 30rpx 60rpx;
|
|
|
|
.popup-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 40rpx;
|
|
|
|
.popup-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
}
|
|
}
|
|
|
|
.quick-actions-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 40rpx;
|
|
|
|
.quick-action-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
padding: 24rpx 16rpx;
|
|
border-radius: 16rpx;
|
|
background: #F8F9FA;
|
|
transition: all 0.3s ease;
|
|
|
|
&:active {
|
|
background: #E9ECEF;
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
.quick-action-text {
|
|
font-size: 24rpx;
|
|
color: #666666;
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 微信小程序适配 */
|
|
@media screen and (max-width: 375px) {
|
|
.custom-navbar {
|
|
padding: 15rpx 25rpx 25rpx;
|
|
}
|
|
|
|
.stats-card {
|
|
margin: 25rpx;
|
|
padding: 30rpx;
|
|
}
|
|
|
|
.pets-list {
|
|
padding: 0 25rpx;
|
|
}
|
|
|
|
.pet-card {
|
|
padding: 25rpx;
|
|
margin-bottom: 25rpx;
|
|
}
|
|
}
|
|
|
|
/* 深色模式适配 */
|
|
@media (prefers-color-scheme: dark) {
|
|
.pets-container {
|
|
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
|
|
}
|
|
|
|
.stats-card,
|
|
.pet-card {
|
|
background: #2d2d2d;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.pet-name {
|
|
color: #ffffff !important;
|
|
}
|
|
|
|
.pet-breed {
|
|
color: #cccccc !important;
|
|
}
|
|
|
|
.pet-age {
|
|
color: #999999 !important;
|
|
}
|
|
}
|
|
</style>
|