1098 lines
24 KiB
Vue
1098 lines
24 KiB
Vue
<template>
|
||
<view class="pets-container">
|
||
<!-- 标签切换容器 -->
|
||
<view class="tabs-container" v-if="petsList.length > 0">
|
||
<view class="tabs-header">
|
||
<view
|
||
class="tab-btn"
|
||
:class="{ active: currentTabIndex === index }"
|
||
v-for="(pet, index) in petsList"
|
||
:key="pet.id"
|
||
@click="switchTab(index)"
|
||
>
|
||
<view class="tab-avatar">{{ getPetEmoji(pet.breed) }}</view>
|
||
<view class="tab-name">{{ pet.name }}</view>
|
||
</view>
|
||
<view class="add-tab" @click="addPet">
|
||
<text style="font-size: 40rpx; margin-bottom: 8rpx;">➕</text>
|
||
<text style="font-size: 20rpx;">添加</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 标签内容 -->
|
||
<view class="tab-content">
|
||
<view
|
||
class="tab-content-panel"
|
||
:class="{ active: currentTabIndex === index }"
|
||
v-for="(pet, index) in petsList"
|
||
:key="pet.id"
|
||
>
|
||
<!-- 宠物详情卡片 -->
|
||
<view class="pet-detail-card">
|
||
<view class="pet-main-avatar">
|
||
<text class="pet-emoji">{{ getPetEmoji(pet.breed) }}</text>
|
||
<view class="pet-status-ring" :class="pet.healthStatus || 'healthy'"></view>
|
||
</view>
|
||
<view class="pet-main-name">{{ pet.name }}</view>
|
||
<view class="pet-main-details">{{ pet.breed }} · {{ pet.age }}岁 · 陪伴{{ pet.companionDays }}天</view>
|
||
<view class="pet-main-tags">
|
||
<text
|
||
class="main-tag"
|
||
v-for="tag in (pet.personality || []).slice(0, 3)"
|
||
:key="tag"
|
||
>{{ tag }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 数据统计网格 -->
|
||
<view class="pet-stats-grid">
|
||
<view class="stat-card">
|
||
<text class="stat-icon">⚖️</text>
|
||
<view class="stat-value">{{ pet.weight || '未知' }}</view>
|
||
<view class="stat-label">当前体重</view>
|
||
</view>
|
||
<view class="stat-card">
|
||
<text class="stat-icon">📝</text>
|
||
<view class="stat-value">{{ getPetRecordsCount(pet.id) }}</view>
|
||
<view class="stat-label">记录数量</view>
|
||
</view>
|
||
<view class="stat-card">
|
||
<text class="stat-icon">💰</text>
|
||
<view class="stat-value">¥{{ getPetMonthlyExpense(pet.id) }}</view>
|
||
<view class="stat-label">本月消费</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮面板 -->
|
||
<view class="pet-actions-panel">
|
||
<view class="action-card" @click="addRecord(pet)">
|
||
<text class="action-icon">📝</text>
|
||
<view class="action-text">添加记录</view>
|
||
</view>
|
||
<view class="action-card" @click="chatWithPet(pet)">
|
||
<text class="action-icon">💬</text>
|
||
<view class="action-text">AI聊天</view>
|
||
</view>
|
||
<view class="action-card" @click="viewHealth(pet)">
|
||
<text class="action-icon">📊</text>
|
||
<view class="action-text">健康档案</view>
|
||
</view>
|
||
<view class="action-card" @click="viewTimeline(pet)">
|
||
<text class="action-icon">📸</text>
|
||
<view class="action-text">成长时光</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 最近活动时间线 -->
|
||
<view class="pet-timeline">
|
||
<view class="timeline-title">⏰ 最近活动</view>
|
||
<view class="timeline-item" v-for="(activity, actIndex) in getPetRecentActivities(pet.id)" :key="actIndex">
|
||
<view class="timeline-dot"></view>
|
||
<view class="timeline-content">
|
||
<view class="timeline-text">{{ activity.text }}</view>
|
||
<view class="timeline-time">{{ activity.time }}</view>
|
||
</view>
|
||
<view class="timeline-type">{{ activity.type }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 健康状态面板 -->
|
||
<view class="pet-health-panel">
|
||
<view class="health-title">❤️ 健康状态</view>
|
||
<view class="health-indicators">
|
||
<view class="health-indicator">
|
||
<view class="health-value">{{ getHealthStatus(pet, 'overall') }}</view>
|
||
<view class="health-label">整体健康</view>
|
||
</view>
|
||
<view class="health-indicator">
|
||
<view class="health-value">{{ getHealthStatus(pet, 'activity') }}</view>
|
||
<view class="health-label">活动水平</view>
|
||
</view>
|
||
<view class="health-indicator">
|
||
<view class="health-value">{{ getHealthStatus(pet, 'appetite') }}</view>
|
||
<view class="health-label">食欲状态</view>
|
||
</view>
|
||
<view class="health-indicator">
|
||
<view class="health-value">{{ getHealthStatus(pet, 'mood') }}</view>
|
||
<view class="health-label">情绪状态</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view class="empty-state" v-else>
|
||
<text class="empty-emoji">🐾</text>
|
||
<text class="empty-title">还没有小伙伴呢</text>
|
||
<text class="empty-desc">添加你的第一只宠物,开始记录美好时光吧~</text>
|
||
<view class="add-first-pet-btn" @click="addPet">
|
||
<text class="add-btn-text">添加第一只宠物</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 家庭概览 -->
|
||
<view class="summary-section" v-if="petsList.length > 0">
|
||
<view class="summary-title">📊 家庭概览</view>
|
||
<view class="summary-stats">
|
||
<view class="summary-card">
|
||
<view class="summary-number">{{ totalRecords }}</view>
|
||
<view class="summary-label">总记录数</view>
|
||
</view>
|
||
<view class="summary-card">
|
||
<view class="summary-number">¥{{ totalMonthlyExpense }}</view>
|
||
<view class="summary-label">本月消费</view>
|
||
</view>
|
||
<view class="summary-card">
|
||
<view class="summary-number">{{ petsList.length }}</view>
|
||
<view class="summary-label">家庭成员</view>
|
||
</view>
|
||
<view class="summary-card">
|
||
<view class="summary-number">{{ upcomingReminders }}</view>
|
||
<view class="summary-label">待办提醒</view>
|
||
</view>
|
||
</view>
|
||
<view class="quick-actions">
|
||
<view class="quick-btn" @click="navigateToRecords">
|
||
<text class="quick-icon">📝</text>
|
||
<text class="quick-text">快速记录</text>
|
||
</view>
|
||
<view class="quick-btn" @click="navigateToStats">
|
||
<text class="quick-icon">💰</text>
|
||
<text class="quick-text">记账</text>
|
||
</view>
|
||
<view class="quick-btn" @click="takePhoto">
|
||
<text class="quick-icon">📸</text>
|
||
<text class="quick-text">拍照</text>
|
||
</view>
|
||
<view class="quick-btn" @click="navigateToAdoption">
|
||
<text class="quick-icon">🏥</text>
|
||
<text class="quick-text">领养</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 浮动添加按钮 -->
|
||
<view class="floating-add" @click="addRecord(petsList[currentTabIndex])">
|
||
<text class="floating-add-icon">📝</text>
|
||
</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="navigateToSettings">
|
||
<u-icon name="setting" 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,
|
||
currentTabIndex: 0,
|
||
petRecords: [],
|
||
petExpenses: []
|
||
}
|
||
},
|
||
onShow() {
|
||
this.loadPets()
|
||
this.loadStatistics()
|
||
this.loadPetRecords()
|
||
this.loadPetExpenses()
|
||
},
|
||
computed: {
|
||
// 计算总陪伴天数
|
||
totalCompanionDays() {
|
||
return this.petsList.reduce((total, pet) => total + (pet.companionDays || 0), 0)
|
||
},
|
||
// 计算总月消费
|
||
totalMonthlyExpense() {
|
||
return this.petExpenses.reduce((total, expense) => total + (expense.amount || 0), 0)
|
||
}
|
||
},
|
||
methods: {
|
||
// 标签切换
|
||
switchTab(index) {
|
||
this.currentTabIndex = index
|
||
},
|
||
|
||
// 获取宠物表情符号
|
||
getPetEmoji(breed) {
|
||
const emojiMap = {
|
||
'橘猫': '🐱',
|
||
'金毛': '🐶',
|
||
'垂耳兔': '🐰',
|
||
'哈士奇': '🐕',
|
||
'波斯猫': '😸',
|
||
'泰迪': '🐩',
|
||
'仓鼠': '🐹',
|
||
'鹦鹉': '🦜'
|
||
}
|
||
return emojiMap[breed] || '🐾'
|
||
},
|
||
|
||
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'
|
||
},
|
||
{
|
||
id: 3,
|
||
name: '小灰',
|
||
breed: '垂耳兔',
|
||
age: 1,
|
||
companionDays: 180,
|
||
avatar: '/static/default-pet.png',
|
||
gender: '母',
|
||
weight: '1.2kg',
|
||
birthday: '2023-06-15',
|
||
healthStatus: 'healthy',
|
||
personality: ['安静', '可爱', '乖巧'],
|
||
lastRecord: '2024-01-13'
|
||
}
|
||
]
|
||
// 保存模拟数据到本地存储
|
||
uni.setStorageSync('pets', pets)
|
||
}
|
||
|
||
this.petsList = pets
|
||
} catch (error) {
|
||
console.error('加载宠物列表失败', error)
|
||
this.petsList = []
|
||
}
|
||
},
|
||
|
||
loadPetRecords() {
|
||
try {
|
||
const records = uni.getStorageSync('petRecords') || []
|
||
this.petRecords = records
|
||
} catch (error) {
|
||
console.error('加载宠物记录失败', error)
|
||
this.petRecords = []
|
||
}
|
||
},
|
||
|
||
loadPetExpenses() {
|
||
try {
|
||
// 模拟宠物消费数据
|
||
const expenses = [
|
||
{ petId: 1, amount: 580, month: '2024-01' },
|
||
{ petId: 2, amount: 890, month: '2024-01' },
|
||
{ petId: 3, amount: 120, month: '2024-01' }
|
||
]
|
||
this.petExpenses = expenses
|
||
} catch (error) {
|
||
console.error('加载宠物消费失败', error)
|
||
this.petExpenses = []
|
||
}
|
||
},
|
||
|
||
loadStatistics() {
|
||
try {
|
||
// 加载统计数据
|
||
const records = uni.getStorageSync('petRecords') || []
|
||
this.totalRecords = records.length || 190
|
||
|
||
// 计算总陪伴天数
|
||
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)
|
||
}
|
||
},
|
||
|
||
// 获取宠物记录数量
|
||
getPetRecordsCount(petId) {
|
||
const petRecords = this.petRecords.filter(record => record.petId === petId)
|
||
const mockCounts = { 1: 89, 2: 67, 3: 34 }
|
||
return petRecords.length || mockCounts[petId] || 0
|
||
},
|
||
|
||
// 获取宠物月消费
|
||
getPetMonthlyExpense(petId) {
|
||
const expense = this.petExpenses.find(exp => exp.petId === petId)
|
||
return expense ? expense.amount : 0
|
||
},
|
||
|
||
// 获取宠物最近活动
|
||
getPetRecentActivities(petId) {
|
||
const activities = {
|
||
1: [
|
||
{ text: '完成了今天的早餐', time: '2小时前', type: '饮食' },
|
||
{ text: '和主人玩了15分钟', time: '4小时前', type: '互动' },
|
||
{ text: '午睡了2小时', time: '6小时前', type: '休息' }
|
||
],
|
||
2: [
|
||
{ text: '外出散步30分钟', time: '1小时前', type: '运动' },
|
||
{ text: '完成了午餐', time: '3小时前', type: '饮食' },
|
||
{ text: '在院子里玩耍', time: '5小时前', type: '互动' }
|
||
],
|
||
3: [
|
||
{ text: '吃了新鲜胡萝卜', time: '1小时前', type: '饮食' },
|
||
{ text: '在笼子里活动', time: '2小时前', type: '运动' },
|
||
{ text: '安静地休息', time: '4小时前', type: '休息' }
|
||
]
|
||
}
|
||
return activities[petId] || []
|
||
},
|
||
|
||
// 获取健康状态
|
||
getHealthStatus(pet, type) {
|
||
const healthData = {
|
||
1: { overall: '优秀', activity: '正常', appetite: '良好', mood: '稳定' },
|
||
2: { overall: '优秀', activity: '活跃', appetite: '良好', mood: '愉快' },
|
||
3: { overall: '良好', activity: '正常', appetite: '良好', mood: '平静' }
|
||
}
|
||
return healthData[pet.id] ? healthData[pet.id][type] : '正常'
|
||
},
|
||
|
||
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/select-record-type?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}`
|
||
})
|
||
},
|
||
|
||
// 导航方法
|
||
navigateToAdoption() {
|
||
uni.navigateTo({
|
||
url: '/pages/adoption/adoption'
|
||
})
|
||
},
|
||
|
||
takePhoto() {
|
||
uni.chooseImage({
|
||
count: 1,
|
||
sizeType: ['original', 'compressed'],
|
||
sourceType: ['camera'],
|
||
success: (res) => {
|
||
uni.showToast({
|
||
title: '拍照成功',
|
||
icon: 'success'
|
||
})
|
||
},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: '拍照失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
|
||
// 快捷操作方法
|
||
navigateToRecords() {
|
||
this.showQuickActions = false
|
||
uni.navigateTo({
|
||
url: '/pages/pets/pet-records'
|
||
})
|
||
},
|
||
|
||
navigateToStats() {
|
||
this.showQuickActions = false
|
||
uni.navigateTo({
|
||
url: '/pages/pets/health-charts'
|
||
})
|
||
},
|
||
|
||
navigateToReminders() {
|
||
this.showQuickActions = false
|
||
uni.showToast({
|
||
title: '提醒功能开发中',
|
||
icon: 'none'
|
||
})
|
||
},
|
||
|
||
navigateToSettings() {
|
||
this.showQuickActions = false
|
||
uni.navigateTo({
|
||
url: '/pages/profile/profile'
|
||
})
|
||
},
|
||
|
||
exportData() {
|
||
this.showQuickActions = false
|
||
uni.showToast({
|
||
title: '数据导出功能开发中',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.pets-container {
|
||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
|
||
min-height: 100vh;
|
||
padding-bottom: 20rpx;
|
||
padding-top: 20rpx;
|
||
}
|
||
|
||
/* 标签切换容器 */
|
||
.tabs-container {
|
||
background: rgba(255, 255, 255, 0.85);
|
||
margin: 20rpx 30rpx 30rpx;
|
||
border-radius: 40rpx;
|
||
backdrop-filter: blur(20rpx);
|
||
overflow: hidden;
|
||
box-shadow: 0 16rpx 64rpx rgba(255, 138, 128, 0.2);
|
||
border: 2rpx solid rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
.tabs-header {
|
||
display: flex;
|
||
background: linear-gradient(135deg, rgba(255, 138, 128, 0.2) 0%, rgba(255, 182, 193, 0.2) 100%);
|
||
padding: 10rpx;
|
||
border-radius: 40rpx 40rpx 0 0;
|
||
position: relative;
|
||
}
|
||
|
||
.tab-btn {
|
||
flex: 1;
|
||
background: none;
|
||
border: none;
|
||
padding: 24rpx 16rpx;
|
||
text-align: center;
|
||
border-radius: 30rpx;
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
z-index: 2;
|
||
|
||
&.active {
|
||
background: rgba(255, 255, 255, 0.9);
|
||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.2);
|
||
}
|
||
|
||
.tab-avatar {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
border-radius: 24rpx;
|
||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 28rpx;
|
||
margin: 0 auto 8rpx;
|
||
}
|
||
|
||
.tab-name {
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.add-tab {
|
||
width: 120rpx;
|
||
background: none;
|
||
border: none;
|
||
padding: 24rpx 16rpx;
|
||
text-align: center;
|
||
border-radius: 30rpx;
|
||
transition: all 0.3s ease;
|
||
color: #FF8A80;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&:active {
|
||
background: rgba(255, 138, 128, 0.15);
|
||
}
|
||
}
|
||
|
||
/* 标签内容 */
|
||
.tab-content {
|
||
padding: 50rpx;
|
||
}
|
||
|
||
.tab-content-panel {
|
||
display: none;
|
||
|
||
&.active {
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
/* 宠物详情卡片 */
|
||
.pet-detail-card {
|
||
text-align: center;
|
||
margin-bottom: 50rpx;
|
||
|
||
.pet-main-avatar {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
border-radius: 80rpx;
|
||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin: 0 auto 30rpx;
|
||
position: relative;
|
||
box-shadow: 0 16rpx 50rpx rgba(255, 138, 128, 0.25);
|
||
|
||
.pet-emoji {
|
||
font-size: 80rpx;
|
||
}
|
||
|
||
.pet-status-ring {
|
||
position: absolute;
|
||
top: -8rpx;
|
||
left: -8rpx;
|
||
right: -8rpx;
|
||
bottom: -8rpx;
|
||
border: 6rpx solid #4CAF50;
|
||
border-radius: 50%;
|
||
border-top-color: transparent;
|
||
animation: spin 3s linear infinite;
|
||
|
||
&.healthy {
|
||
border-color: #4CAF50;
|
||
border-top-color: transparent;
|
||
}
|
||
|
||
&.warning {
|
||
border-color: #FFB74D;
|
||
border-top-color: transparent;
|
||
}
|
||
|
||
&.sick {
|
||
border-color: #FF8A80;
|
||
border-top-color: transparent;
|
||
}
|
||
}
|
||
}
|
||
|
||
.pet-main-name {
|
||
font-size: 44rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.pet-main-details {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.pet-main-tags {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 16rpx;
|
||
margin-bottom: 40rpx;
|
||
flex-wrap: wrap;
|
||
|
||
.main-tag {
|
||
background: #E8F5E8;
|
||
color: #4CAF50;
|
||
padding: 12rpx 24rpx;
|
||
border-radius: 24rpx;
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
/* 数据统计网格 */
|
||
.pet-stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 30rpx;
|
||
margin-bottom: 50rpx;
|
||
|
||
.stat-card {
|
||
background: #F8F9FA;
|
||
padding: 30rpx 20rpx;
|
||
border-radius: 30rpx;
|
||
text-align: center;
|
||
|
||
.stat-icon {
|
||
font-size: 40rpx;
|
||
margin-bottom: 16rpx;
|
||
display: block;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 操作按钮面板 */
|
||
.pet-actions-panel {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 24rpx;
|
||
margin-bottom: 50rpx;
|
||
|
||
.action-card {
|
||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||
color: white;
|
||
border: none;
|
||
padding: 30rpx;
|
||
border-radius: 30rpx;
|
||
text-align: center;
|
||
transition: transform 0.2s;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&:active {
|
||
transform: translateY(-4rpx);
|
||
}
|
||
|
||
.action-icon {
|
||
font-size: 40rpx;
|
||
margin-bottom: 16rpx;
|
||
display: block;
|
||
}
|
||
|
||
.action-text {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 时间线 */
|
||
.pet-timeline {
|
||
background: #F8F9FA;
|
||
border-radius: 30rpx;
|
||
padding: 40rpx;
|
||
margin-bottom: 50rpx;
|
||
|
||
.timeline-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 30rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.timeline-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
padding: 20rpx 0;
|
||
border-bottom: 2rpx solid #E9ECEF;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.timeline-dot {
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-radius: 8rpx;
|
||
background: #FF8A80;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.timeline-content {
|
||
flex: 1;
|
||
|
||
.timeline-text {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
|
||
.timeline-time {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.timeline-type {
|
||
background: #E3F2FD;
|
||
color: #2196F3;
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 16rpx;
|
||
font-size: 18rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 健康状态面板 */
|
||
.pet-health-panel {
|
||
background: linear-gradient(135deg, #FF6B6B, #4ECDC4);
|
||
color: white;
|
||
border-radius: 30rpx;
|
||
padding: 40rpx;
|
||
margin-bottom: 50rpx;
|
||
|
||
.health-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 30rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.health-indicators {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 30rpx;
|
||
|
||
.health-indicator {
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border-radius: 24rpx;
|
||
padding: 24rpx;
|
||
text-align: center;
|
||
|
||
.health-value {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.health-label {
|
||
font-size: 22rpx;
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 空状态 */
|
||
.empty-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 120rpx 60rpx;
|
||
text-align: center;
|
||
|
||
.empty-emoji {
|
||
font-size: 200rpx;
|
||
margin-bottom: 40rpx;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.empty-title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: white;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.empty-desc {
|
||
font-size: 28rpx;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
line-height: 1.5;
|
||
margin-bottom: 60rpx;
|
||
}
|
||
|
||
.add-first-pet-btn {
|
||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||
padding: 24rpx 48rpx;
|
||
border-radius: 50rpx;
|
||
box-shadow: 0 16rpx 64rpx rgba(255, 138, 128, 0.4);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.add-btn-text {
|
||
color: white;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 家庭概览 */
|
||
.summary-section {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
margin: 30rpx;
|
||
border-radius: 40rpx;
|
||
padding: 40rpx;
|
||
backdrop-filter: blur(40rpx);
|
||
box-shadow: 0 16rpx 64rpx rgba(0, 0, 0, 0.1);
|
||
|
||
.summary-title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 30rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.summary-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 30rpx;
|
||
margin-bottom: 40rpx;
|
||
|
||
.summary-card {
|
||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||
color: white;
|
||
padding: 30rpx;
|
||
border-radius: 30rpx;
|
||
text-align: center;
|
||
|
||
.summary-number {
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.summary-label {
|
||
font-size: 24rpx;
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
}
|
||
|
||
.quick-actions {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 20rpx;
|
||
|
||
.quick-btn {
|
||
background: #F8F9FA;
|
||
border: none;
|
||
border-radius: 24rpx;
|
||
padding: 24rpx 16rpx;
|
||
text-align: center;
|
||
transition: transform 0.2s;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&:active {
|
||
transform: translateY(-4rpx);
|
||
}
|
||
|
||
.quick-icon {
|
||
font-size: 32rpx;
|
||
margin-bottom: 8rpx;
|
||
display: block;
|
||
}
|
||
|
||
.quick-text {
|
||
font-size: 20rpx;
|
||
color: #666;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 浮动添加按钮 */
|
||
.floating-add {
|
||
position: fixed;
|
||
bottom: 60rpx;
|
||
right: 40rpx;
|
||
width: 112rpx;
|
||
height: 112rpx;
|
||
border-radius: 56rpx;
|
||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||
color: white;
|
||
border: none;
|
||
box-shadow: 0 8rpx 40rpx rgba(255, 138, 128, 0.4);
|
||
transition: transform 0.3s;
|
||
z-index: 999;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&:active {
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.floating-add-icon {
|
||
font-size: 48rpx;
|
||
}
|
||
}
|
||
|
||
/* 快捷操作弹窗 */
|
||
.quick-actions-popup {
|
||
background: #ffffff;
|
||
border-radius: 40rpx 40rpx 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;
|
||
justify-content: center;
|
||
gap: 16rpx;
|
||
padding: 24rpx 16rpx;
|
||
border-radius: 16rpx;
|
||
background: #F8F9FA;
|
||
transition: all 0.3s ease;
|
||
text-align: center;
|
||
|
||
&:active {
|
||
background: #E9ECEF;
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.quick-action-text {
|
||
font-size: 24rpx;
|
||
color: #666666;
|
||
text-align: center;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 响应式适配 */
|
||
@media screen and (max-width: 375px) {
|
||
.tabs-container,
|
||
.summary-section {
|
||
margin: 15rpx;
|
||
}
|
||
|
||
.tab-content {
|
||
padding: 30rpx;
|
||
}
|
||
|
||
.pet-stats-grid {
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.pet-actions-panel {
|
||
gap: 16rpx;
|
||
}
|
||
}
|
||
|
||
/* 强制保持明亮主题,不受系统暗黑模式影响 */
|
||
</style>
|