pet/pages/pets/pet-detail.vue

969 lines
21 KiB
Vue
Raw Permalink 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="container page-container-with-bg">
<!-- 宠物主卡片 -->
<view class="pet-main-card">
<!-- 编辑按钮 -->
<view class="edit-btn" @click="editPet">
<text class="edit-icon"></text>
</view>
<!-- 宠物头像区域 -->
<view class="pet-avatar-section">
<view class="avatar-container">
<view class="pet-avatar-large" v-if="!petInfo.avatar">
<text class="avatar-placeholder">🐱</text>
</view>
<image
v-else
:src="petInfo.avatar"
class="pet-avatar-large"
mode="aspectFill"
/>
<view class="avatar-badge">
<text class="badge-text">健康</text>
</view>
</view>
</view>
<!-- 宠物信息区域 -->
<view class="pet-info-section">
<text class="pet-name">{{ petInfo.name || '未知宠物' }}</text>
<view class="pet-meta">
<text class="pet-breed">{{ petInfo.breed || '未知品种' }}</text>
<text class="pet-separator">·</text>
<text class="pet-gender">{{ petInfo.gender || '未知' }}</text>
<text class="pet-separator">·</text>
<text class="pet-age">{{ petInfo.age || 0 }}</text>
</view>
<view class="pet-stats">
<view class="stat-item">
<text class="stat-number">{{ petInfo.companionDays || 0 }}</text>
<text class="stat-label">陪伴天数</text>
</view>
<view class="stat-item clickable" @click="goToWeightManagement">
<text class="stat-number">{{ petInfo.weight || '4.2kg' }}</text>
<text class="stat-label">当前体重</text>
<text class="stat-arrow"></text>
</view>
<view class="stat-item">
<text class="stat-number">85</text>
<text class="stat-label">健康评分</text>
</view>
</view>
</view>
</view>
<!-- 详细信息卡片 -->
<view class="details-card">
<view class="card-header">
<text class="card-title">📋 详细档案</text>
</view>
<view class="details-grid">
<view class="detail-row">
<view class="detail-item">
<view class="detail-icon">🎂</view>
<view class="detail-content">
<text class="detail-label">生日</text>
<text class="detail-value">{{ petInfo.birthday || '2022-03-15' }}</text>
</view>
</view>
<view class="detail-item">
<view class="detail-icon">🏠</view>
<view class="detail-content">
<text class="detail-label">到家日期</text>
<text class="detail-value">{{ petInfo.adoptDate || '2022-04-20' }}</text>
</view>
</view>
</view>
<view class="detail-row">
<view class="detail-item clickable" @click="goToVaccineManagement">
<view class="detail-icon">💉</view>
<view class="detail-content">
<text class="detail-label">疫苗状态</text>
<text class="detail-value status-good">已完成</text>
</view>
<text class="detail-arrow"></text>
</view>
<view class="detail-item">
<view class="detail-icon">🏥</view>
<view class="detail-content">
<text class="detail-label">健康状态</text>
<text class="detail-value status-excellent">优秀</text>
</view>
</view>
</view>
</view>
</view>
<!-- 快速操作区域 -->
<view class="quick-actions">
<view class="actions-header">
<text class="actions-title">🚀 快速操作</text>
</view>
<view class="actions-grid">
<view class="action-card primary" @click="addRecord">
<view class="action-icon-bg">
<text class="action-icon">📝</text>
</view>
<text class="action-title">添加记录</text>
<text class="action-subtitle">记录日常点滴</text>
</view>
<view class="action-card secondary" @click="chatWithPet">
<view class="action-icon-bg">
<text class="action-icon">💬</text>
</view>
<text class="action-title">AI聊天</text>
<text class="action-subtitle">智能对话助手</text>
</view>
<view class="action-card accent" @click="viewHealth">
<view class="action-icon-bg">
<text class="action-icon">📊</text>
</view>
<text class="action-title">健康图表</text>
<text class="action-subtitle">数据可视化</text>
</view>
</view>
</view>
<!-- 最近记录 -->
<view class="records-section">
<view class="records-header">
<text class="records-title">📖 最近记录</text>
<view class="view-all-btn" @click="viewAllRecords">
<text class="view-all-text">查看全部</text>
<text class="view-all-arrow"></text>
</view>
</view>
<view class="records-list" v-if="recentRecords.length > 0">
<view class="record-card" v-for="record in recentRecords" :key="record.id">
<view class="record-left">
<view class="record-icon-container">
<text class="record-icon">{{ getRecordIcon(record.type) }}</text>
</view>
<view class="record-info">
<text class="record-title">{{ record.title || record.content }}</text>
<text class="record-content">{{ record.content }}</text>
<text class="record-time">{{ formatDate(record.date) }}</text>
</view>
</view>
<view class="record-right">
<text class="record-arrow"></text>
</view>
</view>
</view>
<view class="empty-state" v-else>
<text class="empty-icon">📝</text>
<text class="empty-title">还没有记录</text>
<text class="empty-subtitle">开始记录宠物的美好时光吧</text>
<view class="empty-action" @click="addRecord">
<text class="empty-action-text">+ 添加第一条记录</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
petId: '',
petInfo: {},
currentLayout: 1,
activeTab: 0,
drawerExpanded: false,
recentRecords: [
{
id: 1,
type: 'weight',
title: '体重记录',
date: '2024-01-20',
content: '今天体重4.2kg比上周增加了0.1kg,成长状态良好'
},
{
id: 2,
type: 'vaccine',
title: '疫苗接种',
date: '2024-01-18',
content: '完成了狂犬疫苗第二针接种,医生说恢复情况很好'
},
{
id: 3,
type: 'bath',
title: '洗澡护理',
date: '2024-01-17',
content: '给小橘洗了澡,全程很乖没有挣扎,现在毛毛很香'
},
{
id: 4,
type: 'weight',
title: '体重记录',
date: '2024-01-15',
content: '体重4.1kg,保持稳定增长趋势'
},
{
id: 5,
type: 'food',
title: '饮食记录',
date: '2024-01-14',
content: '今天食欲很好,吃完了所有的猫粮'
}
],
layout1Items: [
{ id: 1, icon: '📝', text: '添加记录', action: 'addRecord' },
{ id: 2, icon: '💬', text: 'AI聊天', action: 'chatWithPet' },
{ id: 3, icon: '📊', text: '健康档案', action: 'viewHealth' },
{ id: 4, icon: '⏰', text: '成长时光', action: 'viewTimeline' },
{ id: 5, icon: '📋', text: '所有记录', action: 'viewRecords' },
{ id: 6, icon: '🔔', text: '提醒设置', action: 'showReminder' },
{ id: 7, icon: '📷', text: '拍照记录', action: 'takePhoto' },
{ id: 8, icon: '🎵', text: '音频日记', action: 'recordAudio' },
{ id: 9, icon: '🏥', text: '医疗记录', action: 'medicalRecord' }
],
layout2Items: [
{ id: 1, icon: '📝', text: '添加记录', action: 'addRecord' },
{ id: 2, icon: '💬', text: 'AI聊天', action: 'chatWithPet' },
{ id: 3, icon: '📊', text: '健康档案', action: 'viewHealth' },
{ id: 4, icon: '⏰', text: '成长时光', action: 'viewTimeline' },
{ id: 5, icon: '📋', text: '所有记录', action: 'viewRecords' },
{ id: 6, icon: '🔔', text: '提醒设置', action: 'showReminder' },
{ id: 7, icon: '📷', text: '拍照记录', action: 'takePhoto' },
{ id: 8, icon: '🎵', text: '音频日记', action: 'recordAudio' }
],
tabs: [
{
id: 1,
name: '日常',
items: [
{ id: 1, icon: '📝', text: '添加记录', action: 'addRecord' },
{ id: 2, icon: '💬', text: 'AI聊天', action: 'chatWithPet' },
{ id: 3, icon: '📷', text: '拍照记录', action: 'takePhoto' }
]
},
{
id: 2,
name: '健康',
items: [
{ id: 4, icon: '📊', text: '健康档案', action: 'viewHealth' },
{ id: 5, icon: '🏥', text: '医疗记录', action: 'medicalRecord' },
{ id: 6, icon: '💊', text: '用药提醒', action: 'medicineReminder' }
]
},
{
id: 3,
name: '其他',
items: [
{ id: 7, icon: '⏰', text: '成长时光', action: 'viewTimeline' },
{ id: 8, icon: '📋', text: '所有记录', action: 'viewRecords' },
{ id: 9, icon: '🔔', text: '提醒设置', action: 'showReminder' }
]
}
],
layout7Items: [
{ id: 1, icon: '📝', text: '添加记录', action: 'addRecord' },
{ id: 2, icon: '💬', text: 'AI聊天', action: 'chatWithPet' },
{ id: 3, icon: '📊', text: '健康档案', action: 'viewHealth' },
{ id: 4, icon: '⏰', text: '成长时光', action: 'viewTimeline' },
{ id: 5, icon: '📋', text: '所有记录', action: 'viewRecords' },
{ id: 6, icon: '🔔', text: '提醒设置', action: 'showReminder' }
]
}
},
onLoad(options) {
this.petId = options.id
this.loadPetInfo()
},
methods: {
loadPetInfo() {
try {
// 从本地存储获取宠物信息
const pets = uni.getStorageSync('pets') || []
this.petInfo = pets.find(pet => pet.id == this.petId) || {}
// 如果没有找到宠物信息,使用默认数据
if (!this.petInfo.id) {
this.petInfo = {
id: this.petId,
name: '小橘',
breed: '橘猫',
age: 2,
companionDays: 645,
avatar: '',
gender: '公',
weight: '4.2kg',
birthday: '2022-03-15',
adoptDate: '2022-04-20'
}
}
} catch (error) {
console.error('加载宠物信息失败', error)
this.petInfo = {}
}
},
getRecordIcon(type) {
const icons = {
weight: '⚖️',
vaccine: '💉',
bath: '🛁',
food: '🍽️',
play: '🎾',
medical: '🏥',
default: '📝'
}
return icons[type] || icons.default
},
formatDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const now = new Date()
const diff = now - date
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
if (days === 0) return '今天'
if (days === 1) return '昨天'
if (days < 7) return `${days}天前`
return dateStr
},
editPet() {
uni.navigateTo({
url: `/pages/pets/edit-pet?id=${this.petId}`
})
},
addRecord() {
uni.navigateTo({
url: `/pages/pets/select-record-type?petId=${this.petId}`
})
},
chatWithPet() {
uni.navigateTo({
url: `/pages/pets/pet-chat-simple?petId=${this.petId}`
})
},
viewHealth() {
uni.navigateTo({
url: `/pages/pets/health-charts?petId=${this.petId}`
})
},
setPersonality() {
uni.navigateTo({
url: `/pages/pets/pet-personality?petId=${this.petId}`
})
},
viewTimeline() {
uni.navigateTo({
url: `/pages/pets/pet-timeline?petId=${this.petId}`
})
},
viewRecords() {
uni.navigateTo({
url: `/pages/pets/pet-records?petId=${this.petId}`
})
},
viewAllRecords() {
this.viewRecords()
},
goToWeightManagement() {
uni.navigateTo({
url: `/pages/pets/pet-weight?petId=${this.petId}&petName=${this.petInfo.name}`
})
},
goToVaccineManagement() {
uni.navigateTo({
url: `/pages/pets/pet-vaccine?petId=${this.petId}&petName=${this.petInfo.name}`
})
},
shareProfile() {
uni.showToast({
title: '分享功能开发中',
icon: 'none'
})
},
switchLayout(layoutNumber) {
this.currentLayout = layoutNumber
},
handleAction(action) {
switch(action) {
case 'addRecord':
this.addRecord()
break
case 'chatWithPet':
this.chatWithPet()
break
case 'viewHealth':
this.viewHealth()
break
case 'viewTimeline':
this.viewTimeline()
break
case 'viewRecords':
this.viewRecords()
break
case 'showReminder':
uni.showToast({
title: '提醒功能开发中',
icon: 'none'
})
break
case 'takePhoto':
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['camera'],
success: () => {
uni.showToast({
title: '拍照成功',
icon: 'success'
})
}
})
break
case 'recordAudio':
uni.showToast({
title: '音频功能开发中',
icon: 'none'
})
break
case 'medicalRecord':
uni.showToast({
title: '医疗记录功能开发中',
icon: 'none'
})
break
case 'medicineReminder':
uni.showToast({
title: '用药提醒功能开发中',
icon: 'none'
})
break
default:
console.log('未知操作:', action)
}
}
}
}
</script>
<style lang="scss" scoped>
/* 优化后的样式 */
.container {
padding: 20rpx;
}
/* 宠物主卡片 */
.pet-main-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 32rpx;
padding: 40rpx;
margin-bottom: 24rpx;
box-shadow: 0 12rpx 40rpx rgba(255, 138, 128, 0.25);
border: 1rpx solid rgba(255, 255, 255, 0.3);
position: relative;
.edit-btn {
position: absolute;
top: 24rpx;
right: 24rpx;
width: 56rpx;
height: 56rpx;
background: rgba(255, 138, 128, 0.1);
border-radius: 28rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&:active {
transform: scale(0.9);
background: rgba(255, 138, 128, 0.2);
}
.edit-icon {
font-size: 28rpx;
}
}
.pet-avatar-section {
text-align: center;
margin-bottom: 32rpx;
.avatar-container {
position: relative;
display: inline-block;
.pet-avatar-large {
width: 140rpx;
height: 140rpx;
border-radius: 70rpx;
border: 4rpx solid #FF8A80;
background: #FFE0DD;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.3);
.avatar-placeholder {
font-size: 70rpx;
}
}
.avatar-badge {
position: absolute;
bottom: 8rpx;
right: 8rpx;
background: #4CAF50;
border-radius: 20rpx;
padding: 6rpx 12rpx;
box-shadow: 0 4rpx 12rpx rgba(76, 175, 80, 0.3);
.badge-text {
font-size: 20rpx;
color: white;
font-weight: bold;
}
}
}
}
.pet-info-section {
text-align: center;
.pet-name {
font-size: 44rpx;
font-weight: bold;
color: #333333;
margin-bottom: 16rpx;
display: block;
}
.pet-meta {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 32rpx;
flex-wrap: wrap;
.pet-breed, .pet-gender, .pet-age {
font-size: 28rpx;
color: #666666;
}
.pet-separator {
font-size: 28rpx;
color: #CCCCCC;
margin: 0 12rpx;
}
}
.pet-stats {
display: flex;
justify-content: space-around;
background: rgba(255, 138, 128, 0.05);
border-radius: 24rpx;
padding: 24rpx;
.stat-item {
text-align: center;
position: relative;
&.clickable {
cursor: pointer;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
}
.stat-arrow {
position: absolute;
top: 8rpx;
right: 8rpx;
font-size: 20rpx;
color: #CCCCCC;
}
}
.stat-number {
font-size: 32rpx;
font-weight: bold;
color: #FF8A80;
display: block;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 22rpx;
color: #999999;
display: block;
}
}
}
}
}
/* 详细信息卡片 */
.details-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.card-header {
margin-bottom: 28rpx;
.card-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.details-grid {
.detail-row {
display: flex;
gap: 20rpx;
margin-bottom: 24rpx;
&:last-child {
margin-bottom: 0;
}
.detail-item {
flex: 1;
display: flex;
align-items: center;
gap: 16rpx;
background: rgba(255, 138, 128, 0.05);
border-radius: 20rpx;
padding: 20rpx;
position: relative;
&.clickable {
cursor: pointer;
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
background: rgba(255, 138, 128, 0.1);
}
.detail-arrow {
position: absolute;
top: 50%;
right: 16rpx;
transform: translateY(-50%);
font-size: 24rpx;
color: #CCCCCC;
}
}
.detail-icon {
font-size: 32rpx;
width: 48rpx;
text-align: center;
}
.detail-content {
flex: 1;
.detail-label {
font-size: 22rpx;
color: #999999;
margin-bottom: 6rpx;
display: block;
}
.detail-value {
font-size: 26rpx;
font-weight: 500;
color: #333333;
display: block;
&.status-good {
color: #4CAF50;
}
&.status-excellent {
color: #FF8A80;
}
}
}
}
}
}
}
/* 快速操作区域 */
.quick-actions {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.actions-header {
margin-bottom: 28rpx;
.actions-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.actions-grid {
display: flex;
gap: 16rpx;
.action-card {
flex: 1;
border-radius: 20rpx;
padding: 24rpx 16rpx;
text-align: center;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&:active {
transform: scale(0.95);
}
&.primary {
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
color: white;
}
&.secondary {
background: linear-gradient(135deg, #64B5F6, #81C784);
color: white;
}
&.accent {
background: linear-gradient(135deg, #FFB74D, #FF8A65);
color: white;
}
.action-icon-bg {
width: 56rpx;
height: 56rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 28rpx;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 16rpx;
.action-icon {
font-size: 32rpx;
}
}
.action-title {
font-size: 26rpx;
font-weight: bold;
margin-bottom: 6rpx;
display: block;
}
.action-subtitle {
font-size: 20rpx;
opacity: 0.8;
display: block;
}
}
}
}
/* 记录区域 */
.records-section {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 28rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.records-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 28rpx;
.records-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
.view-all-btn {
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 16rpx;
background: rgba(255, 138, 128, 0.1);
border-radius: 20rpx;
transition: all 0.3s ease;
&:active {
background: rgba(255, 138, 128, 0.2);
}
.view-all-text {
font-size: 24rpx;
color: #FF8A80;
}
.view-all-arrow {
font-size: 20rpx;
color: #FF8A80;
}
}
}
.records-list {
.record-card {
display: flex;
align-items: center;
padding: 20rpx;
background: rgba(255, 138, 128, 0.03);
border-radius: 20rpx;
margin-bottom: 16rpx;
transition: all 0.3s ease;
&:last-child {
margin-bottom: 0;
}
&:active {
background: rgba(255, 138, 128, 0.08);
transform: scale(0.98);
}
.record-left {
flex: 1;
display: flex;
align-items: center;
gap: 16rpx;
.record-icon-container {
width: 56rpx;
height: 56rpx;
background: #FF8A80;
border-radius: 28rpx;
display: flex;
align-items: center;
justify-content: center;
.record-icon {
font-size: 28rpx;
color: white;
}
}
.record-info {
flex: 1;
.record-title {
font-size: 28rpx;
font-weight: 500;
color: #333333;
margin-bottom: 6rpx;
display: block;
}
.record-content {
font-size: 24rpx;
color: #666666;
line-height: 1.4;
margin-bottom: 6rpx;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.record-time {
font-size: 20rpx;
color: #999999;
display: block;
}
}
}
.record-right {
.record-arrow {
font-size: 32rpx;
color: #CCCCCC;
}
}
}
}
.empty-state {
text-align: center;
padding: 80rpx 40rpx;
.empty-icon {
font-size: 80rpx;
margin-bottom: 24rpx;
display: block;
}
.empty-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
margin-bottom: 12rpx;
display: block;
}
.empty-subtitle {
font-size: 26rpx;
color: #999999;
margin-bottom: 40rpx;
display: block;
}
.empty-action {
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
border-radius: 28rpx;
padding: 20rpx 40rpx;
display: inline-block;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
}
.empty-action-text {
font-size: 28rpx;
color: white;
font-weight: 500;
}
}
}
}
</style>