This commit is contained in:
parent
4e136fb467
commit
c7b0b1e5b7
16
pages.json
16
pages.json
|
|
@ -32,6 +32,14 @@
|
|||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/adoption/adoption-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "领养详情",
|
||||
"navigationBarBackgroundColor": "#FF8A80",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/profile/profile",
|
||||
"style": {
|
||||
|
|
@ -80,6 +88,14 @@
|
|||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pets/record-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "记录详情",
|
||||
"navigationBarBackgroundColor": "#FF8A80",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/pets/pet-chat-simple",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,749 @@
|
|||
<template>
|
||||
<view class="adoption-detail-container">
|
||||
<!-- 宠物图片轮播 -->
|
||||
<view class="pet-gallery">
|
||||
<swiper
|
||||
class="gallery-swiper"
|
||||
:indicator-dots="pet.photos && pet.photos.length > 1"
|
||||
:autoplay="false"
|
||||
:circular="true"
|
||||
indicator-color="rgba(255,255,255,0.5)"
|
||||
indicator-active-color="#FF8A80"
|
||||
>
|
||||
<swiper-item v-for="(photo, index) in pet.photos" :key="index">
|
||||
<image
|
||||
class="gallery-image"
|
||||
:src="photo"
|
||||
mode="aspectFill"
|
||||
@click="previewImage(photo, index)"
|
||||
/>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
||||
<!-- 状态标识 -->
|
||||
<view class="pet-status-overlay" :class="pet.status">
|
||||
<text class="status-icon">{{ getStatusIcon() }}</text>
|
||||
<text class="status-text">{{ getStatusText() }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 收藏按钮 -->
|
||||
<view class="favorite-btn" @click="toggleFavorite">
|
||||
<text class="favorite-icon">{{ pet.isFavorite ? '❤️' : '🤍' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 宠物基本信息 -->
|
||||
<view class="pet-basic-info">
|
||||
<view class="pet-header">
|
||||
<text class="pet-name">{{ pet.name }}</text>
|
||||
<view class="pet-stats">
|
||||
<view class="stat-item">
|
||||
<text class="stat-icon">👁️</text>
|
||||
<text class="stat-count">{{ pet.views }}</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-icon">❤️</text>
|
||||
<text class="stat-count">{{ pet.favorites }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="pet-tags">
|
||||
<view class="tag-item type-tag">
|
||||
<text class="tag-text">{{ getPetTypeName() }}</text>
|
||||
</view>
|
||||
<view class="tag-item breed-tag">
|
||||
<text class="tag-text">{{ getPetBreedName() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="pet-details-grid">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">年龄</text>
|
||||
<text class="detail-value">{{ pet.age }}岁</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">性别</text>
|
||||
<text class="detail-value">{{ pet.gender === 'male' ? '公' : '母' }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">地区</text>
|
||||
<text class="detail-value">{{ getLocationText() }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">健康</text>
|
||||
<text class="detail-value">{{ pet.health }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 宠物描述 -->
|
||||
<view class="pet-description">
|
||||
<view class="section-title">
|
||||
<text class="title-text">🐾 关于{{ pet.name }}</text>
|
||||
</view>
|
||||
<text class="description-text">{{ pet.description }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 性格特点 -->
|
||||
<view class="pet-personality" v-if="pet.personality && pet.personality.length > 0">
|
||||
<view class="section-title">
|
||||
<text class="title-text">😊 性格特点</text>
|
||||
</view>
|
||||
<view class="personality-tags">
|
||||
<view
|
||||
class="personality-tag"
|
||||
v-for="trait in pet.personality"
|
||||
:key="trait"
|
||||
>
|
||||
<text class="trait-text">{{ trait }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 领养条件 -->
|
||||
<view class="adoption-requirements" v-if="pet.requirements && pet.requirements.length > 0">
|
||||
<view class="section-title">
|
||||
<text class="title-text">📋 领养条件</text>
|
||||
</view>
|
||||
<view class="requirements-list">
|
||||
<view
|
||||
class="requirement-item"
|
||||
v-for="(requirement, index) in pet.requirements"
|
||||
:key="index"
|
||||
>
|
||||
<text class="requirement-icon">✓</text>
|
||||
<text class="requirement-text">{{ requirement }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系信息 */
|
||||
<view class="contact-info">
|
||||
<view class="section-title">
|
||||
<text class="title-text">📞 联系方式</text>
|
||||
</view>
|
||||
<view class="contact-details">
|
||||
<view class="contact-item">
|
||||
<text class="contact-label">联系人:</text>
|
||||
<text class="contact-value">{{ pet.contact.name }}</text>
|
||||
<text class="contact-type-badge">{{ pet.contact.type === 'organization' ? '机构' : '个人' }}</text>
|
||||
</view>
|
||||
<view class="contact-item">
|
||||
<text class="contact-label">电话:</text>
|
||||
<text class="contact-value">{{ pet.contact.phone }}</text>
|
||||
<view class="contact-action" @click="makeCall">
|
||||
<text class="action-text">拨打</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="contact-item" v-if="pet.contact.wechat">
|
||||
<text class="contact-label">微信:</text>
|
||||
<text class="contact-value">{{ pet.contact.wechat }}</text>
|
||||
<view class="contact-action" @click="copyWechat">
|
||||
<text class="action-text">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="contact-item" v-if="pet.location.address">
|
||||
<text class="contact-label">地址:</text>
|
||||
<text class="contact-value">{{ pet.location.address }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 发布信息 */
|
||||
<view class="publish-info">
|
||||
<view class="publish-item">
|
||||
<text class="publish-label">发布时间:</text>
|
||||
<text class="publish-value">{{ formatTime(pet.publishTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<view class="bottom-actions">
|
||||
<view class="action-btn secondary" @click="shareAdoption">
|
||||
<text class="btn-icon">📤</text>
|
||||
<text class="btn-text">分享</text>
|
||||
</view>
|
||||
<view class="action-btn primary" @click="applyAdoption" v-if="pet.status === 'available'">
|
||||
<text class="btn-text">申请领养</text>
|
||||
</view>
|
||||
<view class="action-btn disabled" v-else>
|
||||
<text class="btn-text">{{ getStatusText() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import adoptionManager from '@/utils/adoptionManager.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
petId: '',
|
||||
pet: {
|
||||
photos: [],
|
||||
personality: [],
|
||||
requirements: [],
|
||||
contact: {},
|
||||
location: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.petId = options.petId || ''
|
||||
this.loadPetDetail()
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadPetDetail() {
|
||||
const pets = adoptionManager.getAdoptionPets()
|
||||
this.pet = pets.find(p => p.id == this.petId) || {}
|
||||
|
||||
// 设置页面标题
|
||||
if (this.pet.name) {
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.pet.name + '的领养信息'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getPetTypeName() {
|
||||
return adoptionManager.getPetTypeName(this.pet.type)
|
||||
},
|
||||
|
||||
getPetBreedName() {
|
||||
return adoptionManager.getPetBreedName(this.pet.type, this.pet.breed)
|
||||
},
|
||||
|
||||
getLocationText() {
|
||||
return adoptionManager.getLocationName(
|
||||
this.pet.location.province,
|
||||
this.pet.location.city,
|
||||
this.pet.location.district
|
||||
)
|
||||
},
|
||||
|
||||
getStatusIcon() {
|
||||
return adoptionManager.getStatusInfo(this.pet.status).icon
|
||||
},
|
||||
|
||||
getStatusText() {
|
||||
return adoptionManager.getStatusInfo(this.pet.status).name
|
||||
},
|
||||
|
||||
formatTime(timeStr) {
|
||||
if (!timeStr) return ''
|
||||
|
||||
const time = new Date(timeStr)
|
||||
const now = new Date()
|
||||
const diff = now - time
|
||||
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (days === 0) {
|
||||
return '今天发布'
|
||||
} else if (days === 1) {
|
||||
return '昨天发布'
|
||||
} else if (days < 7) {
|
||||
return `${days}天前发布`
|
||||
} else {
|
||||
return `${time.getFullYear()}-${(time.getMonth() + 1).toString().padStart(2, '0')}-${time.getDate().toString().padStart(2, '0')} 发布`
|
||||
}
|
||||
},
|
||||
|
||||
previewImage(photo, index) {
|
||||
uni.previewImage({
|
||||
urls: this.pet.photos,
|
||||
current: index
|
||||
})
|
||||
},
|
||||
|
||||
toggleFavorite() {
|
||||
this.pet.isFavorite = !this.pet.isFavorite
|
||||
adoptionManager.toggleFavorite(this.petId, this.pet.isFavorite)
|
||||
|
||||
uni.showToast({
|
||||
title: this.pet.isFavorite ? '已收藏' : '已取消收藏',
|
||||
icon: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
},
|
||||
|
||||
makeCall() {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: this.pet.contact.phone.replace(/\*/g, ''),
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '拨打失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
copyWechat() {
|
||||
uni.setClipboardData({
|
||||
data: this.pet.contact.wechat,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '微信号已复制',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
shareAdoption() {
|
||||
uni.share({
|
||||
provider: 'weixin',
|
||||
scene: 'WXSceneSession',
|
||||
type: 0,
|
||||
href: '',
|
||||
title: `${this.pet.name}等待领养`,
|
||||
summary: this.pet.description,
|
||||
imageUrl: this.pet.photos[0],
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '分享成功',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '分享失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
applyAdoption() {
|
||||
uni.showModal({
|
||||
title: '申请领养',
|
||||
content: `确定要申请领养${this.pet.name}吗?我们会将您的联系方式转达给发布者。`,
|
||||
confirmText: '确定申请',
|
||||
cancelText: '再想想',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 这里可以跳转到申请表单页面或者直接联系发布者
|
||||
uni.showToast({
|
||||
title: '申请已提交',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 模拟申请后的状态变化
|
||||
setTimeout(() => {
|
||||
this.pet.status = 'pending'
|
||||
uni.showToast({
|
||||
title: '请耐心等待回复',
|
||||
icon: 'none'
|
||||
})
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.adoption-detail-container {
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
|
||||
min-height: 100vh;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
/* 宠物图片轮播 */
|
||||
.pet-gallery {
|
||||
position: relative;
|
||||
height: 600rpx;
|
||||
|
||||
.gallery-swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.gallery-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.pet-status-overlay {
|
||||
position: absolute;
|
||||
top: 32rpx;
|
||||
left: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
border-radius: 16rpx;
|
||||
padding: 12rpx 20rpx;
|
||||
|
||||
&.available {
|
||||
background: rgba(76, 175, 80, 0.9);
|
||||
}
|
||||
|
||||
&.reserved {
|
||||
background: rgba(255, 152, 0, 0.9);
|
||||
}
|
||||
|
||||
&.adopted {
|
||||
background: rgba(158, 158, 158, 0.9);
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 22rpx;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.favorite-btn {
|
||||
position: absolute;
|
||||
top: 32rpx;
|
||||
right: 32rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.favorite-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 宠物基本信息 */
|
||||
.pet-basic-info {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
margin: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.pet-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.pet-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.pet-stats {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
|
||||
.stat-icon {
|
||||
font-size: 18rpx;
|
||||
}
|
||||
|
||||
.stat-count {
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pet-tags {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.tag-item {
|
||||
border-radius: 16rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
|
||||
&.type-tag {
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
|
||||
.tag-text {
|
||||
color: #FF8A80;
|
||||
}
|
||||
}
|
||||
|
||||
&.breed-tag {
|
||||
background: rgba(33, 150, 243, 0.1);
|
||||
|
||||
.tag-text {
|
||||
color: #2196F3;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-text {
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pet-details-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16rpx;
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
|
||||
.detail-label {
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 通用卡片样式 */
|
||||
.pet-description,
|
||||
.pet-personality,
|
||||
.adoption-requirements,
|
||||
.contact-info,
|
||||
.publish-info {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
margin: 0 20rpx 16rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.title-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 宠物描述 */
|
||||
.pet-description {
|
||||
.description-text {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
/* 性格特点 */
|
||||
.pet-personality {
|
||||
.personality-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
|
||||
.personality-tag {
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
border-radius: 16rpx;
|
||||
padding: 12rpx 20rpx;
|
||||
|
||||
.trait-text {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 领养条件 */
|
||||
.adoption-requirements {
|
||||
.requirements-list {
|
||||
.requirement-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.requirement-icon {
|
||||
font-size: 20rpx;
|
||||
color: #4CAF50;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.requirement-text {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 联系信息 */
|
||||
.contact-info {
|
||||
.contact-details {
|
||||
.contact-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.contact-label {
|
||||
font-size: 22rpx;
|
||||
color: #999999;
|
||||
min-width: 100rpx;
|
||||
}
|
||||
|
||||
.contact-value {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.contact-type-badge {
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
border-radius: 12rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
font-size: 18rpx;
|
||||
color: #FF8A80;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.contact-action {
|
||||
background: #FF8A80;
|
||||
border-radius: 12rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
margin-left: 12rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 20rpx;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 发布信息 */
|
||||
.publish-info {
|
||||
.publish-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.publish-label {
|
||||
font-size: 22rpx;
|
||||
color: #999999;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.publish-value {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 底部操作按钮 */
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
padding: 20rpx 32rpx;
|
||||
border-top: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8rpx;
|
||||
flex: 0 0 120rpx;
|
||||
|
||||
.btn-icon {
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 22rpx;
|
||||
color: #FF8A80;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
|
||||
.btn-text {
|
||||
font-size: 28rpx;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: #CCCCCC;
|
||||
|
||||
.btn-text {
|
||||
font-size: 28rpx;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -38,7 +38,7 @@
|
|||
</u-card>
|
||||
</u-form>
|
||||
|
||||
<view class="submit-section">
|
||||
<view class="submit-section">
|
||||
<u-button type="primary" text="保存记录" @click="submitForm" :loading="loading"></u-button>
|
||||
</view>
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,626 @@
|
|||
<template>
|
||||
<view class="record-detail-container">
|
||||
<!-- 记录头部信息 -->
|
||||
<view class="record-header">
|
||||
<view class="header-info">
|
||||
<view class="category-info">
|
||||
<text class="category-icon">{{ getCategoryIcon() }}</text>
|
||||
<text class="category-name">{{ getCategoryName() }}</text>
|
||||
</view>
|
||||
<text class="record-time">{{ formatTime(record.recordTime) }}</text>
|
||||
</view>
|
||||
<view class="share-info">
|
||||
<text class="share-icon">{{ getShareIcon() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 记录内容 -->
|
||||
<view class="record-content">
|
||||
<text class="record-title">{{ record.title }}</text>
|
||||
<text class="record-text">{{ record.content }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 标签 -->
|
||||
<view class="record-tags" v-if="record.tags && record.tags.length > 0">
|
||||
<view class="tags-title">
|
||||
<text class="title-text">🏷️ 标签</text>
|
||||
</view>
|
||||
<view class="tags-list">
|
||||
<view
|
||||
class="tag-item"
|
||||
v-for="tag in record.tags"
|
||||
:key="tag"
|
||||
>
|
||||
<text class="tag-text"># {{ tag }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图片展示 -->
|
||||
<view class="record-photos" v-if="record.photos && record.photos.length > 0">
|
||||
<view class="photos-title">
|
||||
<text class="title-text">📷 图片</text>
|
||||
</view>
|
||||
<view class="photos-grid">
|
||||
<view
|
||||
class="photo-item"
|
||||
v-for="(photo, index) in record.photos"
|
||||
:key="index"
|
||||
@click="previewImage(photo, index)"
|
||||
>
|
||||
<image class="photo-image" :src="photo" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 详细信息 -->
|
||||
<view class="record-details" v-if="hasDetails()">
|
||||
<view class="details-title">
|
||||
<text class="title-text">📋 详细信息</text>
|
||||
</view>
|
||||
<view class="details-list">
|
||||
<view class="detail-item" v-if="record.location">
|
||||
<text class="detail-label">📍 地点:</text>
|
||||
<text class="detail-value">{{ record.location }}</text>
|
||||
</view>
|
||||
<view class="detail-item" v-if="record.weather">
|
||||
<text class="detail-label">🌤️ 天气:</text>
|
||||
<text class="detail-value">{{ record.weather }}</text>
|
||||
</view>
|
||||
<view class="detail-item" v-if="record.mood">
|
||||
<text class="detail-label">😊 心情:</text>
|
||||
<text class="detail-value">{{ getMoodText() }}</text>
|
||||
</view>
|
||||
<view class="detail-item" v-if="record.amount">
|
||||
<text class="detail-label">💰 金额:</text>
|
||||
<text class="detail-value">¥{{ record.amount }}</text>
|
||||
</view>
|
||||
<view class="detail-item" v-if="record.store">
|
||||
<text class="detail-label">🏪 商店:</text>
|
||||
<text class="detail-value">{{ record.store }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 社交数据 -->
|
||||
<view class="social-section">
|
||||
<view class="social-stats">
|
||||
<view class="stat-item" @click="toggleLike">
|
||||
<text class="stat-icon" :class="{ liked: isLiked }">{{ isLiked ? '❤️' : '🤍' }}</text>
|
||||
<text class="stat-count">{{ socialData.likes }}</text>
|
||||
<text class="stat-label">喜欢</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-icon">👁️</text>
|
||||
<text class="stat-count">{{ socialData.views }}</text>
|
||||
<text class="stat-label">浏览</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-icon">💬</text>
|
||||
<text class="stat-count">{{ socialData.comments.length }}</text>
|
||||
<text class="stat-label">评论</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 评论区域 -->
|
||||
<view class="comments-section">
|
||||
<view class="comments-header">
|
||||
<text class="comments-title">💬 评论 ({{ socialData.comments.length }})</text>
|
||||
</view>
|
||||
|
||||
<!-- 评论列表 -->
|
||||
<view class="comments-list" v-if="socialData.comments.length > 0">
|
||||
<view
|
||||
class="comment-item"
|
||||
v-for="comment in socialData.comments"
|
||||
:key="comment.id"
|
||||
>
|
||||
<view class="comment-avatar">
|
||||
<text class="avatar-text">{{ comment.user.charAt(0) }}</text>
|
||||
</view>
|
||||
<view class="comment-content">
|
||||
<view class="comment-header">
|
||||
<text class="comment-user">{{ comment.user }}</text>
|
||||
<text class="comment-time">{{ comment.time }}</text>
|
||||
</view>
|
||||
<text class="comment-text">{{ comment.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空评论状态 -->
|
||||
<view class="empty-comments" v-else>
|
||||
<text class="empty-text">还没有评论,来说点什么吧~</text>
|
||||
</view>
|
||||
|
||||
<!-- 添加评论 -->
|
||||
<view class="add-comment">
|
||||
<view class="comment-input-wrapper">
|
||||
<input
|
||||
class="comment-input"
|
||||
v-model="newComment"
|
||||
placeholder="写下你的评论..."
|
||||
@confirm="addComment"
|
||||
/>
|
||||
<view class="comment-send" @click="addComment" v-if="newComment.trim()">
|
||||
<text class="send-text">发送</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import recordManager from '@/utils/recordManager.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
recordId: '',
|
||||
petId: '',
|
||||
petName: '',
|
||||
record: {},
|
||||
socialData: {
|
||||
likes: 0,
|
||||
views: 0,
|
||||
comments: [],
|
||||
likedBy: []
|
||||
},
|
||||
isLiked: false,
|
||||
newComment: ''
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.recordId = options.recordId || ''
|
||||
this.petId = options.petId || ''
|
||||
this.petName = options.petName || '宠物'
|
||||
this.loadRecordDetail()
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadRecordDetail() {
|
||||
// 获取记录详情
|
||||
const records = recordManager.getRecords(this.petId)
|
||||
this.record = records.find(r => r.id == this.recordId) || {}
|
||||
|
||||
// 获取社交数据
|
||||
this.socialData = recordManager.getSocialData(this.recordId)
|
||||
this.isLiked = this.socialData.likedBy.includes('current_user')
|
||||
},
|
||||
|
||||
getCategoryIcon() {
|
||||
return recordManager.getCategoryInfo(this.record.category, this.record.subCategory).icon
|
||||
},
|
||||
|
||||
getCategoryName() {
|
||||
return recordManager.getCategoryInfo(this.record.category, this.record.subCategory).name
|
||||
},
|
||||
|
||||
getShareIcon() {
|
||||
const icons = {
|
||||
'public': '🌍',
|
||||
'family': '👨👩👧👦',
|
||||
'private': '🔒'
|
||||
}
|
||||
return icons[this.record.shareLevel] || '👨👩👧👦'
|
||||
},
|
||||
|
||||
getMoodText() {
|
||||
const moods = {
|
||||
'happy': '开心',
|
||||
'excited': '兴奋',
|
||||
'calm': '平静',
|
||||
'proud': '自豪',
|
||||
'sad': '难过',
|
||||
'worried': '担心'
|
||||
}
|
||||
return moods[this.record.mood] || this.record.mood
|
||||
},
|
||||
|
||||
formatTime(timeStr) {
|
||||
if (!timeStr) return ''
|
||||
|
||||
const time = new Date(timeStr)
|
||||
const now = new Date()
|
||||
const diff = now - time
|
||||
|
||||
const minutes = Math.floor(diff / (1000 * 60))
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (minutes < 60) {
|
||||
return minutes <= 0 ? '刚刚' : `${minutes}分钟前`
|
||||
} else if (hours < 24) {
|
||||
return `${hours}小时前`
|
||||
} else if (days < 7) {
|
||||
return `${days}天前`
|
||||
} else {
|
||||
return `${time.getFullYear()}-${(time.getMonth() + 1).toString().padStart(2, '0')}-${time.getDate().toString().padStart(2, '0')}`
|
||||
}
|
||||
},
|
||||
|
||||
hasDetails() {
|
||||
return this.record.location || this.record.weather || this.record.mood || this.record.amount || this.record.store
|
||||
},
|
||||
|
||||
previewImage(photo, index) {
|
||||
uni.previewImage({
|
||||
urls: this.record.photos,
|
||||
current: index
|
||||
})
|
||||
},
|
||||
|
||||
toggleLike() {
|
||||
const newSocialData = recordManager.likeRecord(this.recordId, 'current_user')
|
||||
if (newSocialData) {
|
||||
this.socialData = newSocialData
|
||||
this.isLiked = this.socialData.likedBy.includes('current_user')
|
||||
}
|
||||
},
|
||||
|
||||
addComment() {
|
||||
if (!this.newComment.trim()) return
|
||||
|
||||
const comment = recordManager.addComment(this.recordId, this.newComment.trim(), '我')
|
||||
if (comment) {
|
||||
this.socialData.comments.unshift(comment)
|
||||
this.newComment = ''
|
||||
|
||||
uni.showToast({
|
||||
title: '评论成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.record-detail-container {
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 记录头部 */
|
||||
.record-header {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.header-info {
|
||||
flex: 1;
|
||||
|
||||
.category-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.category-icon {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
.share-info {
|
||||
.share-icon {
|
||||
font-size: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 记录内容 */
|
||||
.record-content {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.record-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
margin-bottom: 16rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.record-text {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
line-height: 1.6;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* 标签、图片、详细信息通用样式 */
|
||||
.record-tags,
|
||||
.record-photos,
|
||||
.record-details {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.tags-title,
|
||||
.photos-title,
|
||||
.details-title {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.title-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 标签列表 */
|
||||
.tags-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
|
||||
.tag-item {
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
border-radius: 16rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
|
||||
.tag-text {
|
||||
font-size: 22rpx;
|
||||
color: #FF8A80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 图片网格 */
|
||||
.photos-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12rpx;
|
||||
|
||||
.photo-item {
|
||||
aspect-ratio: 1;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.photo-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 详细信息列表 */
|
||||
.details-list {
|
||||
.detail-item {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 22rpx;
|
||||
color: #999999;
|
||||
min-width: 120rpx;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 社交数据 */
|
||||
.social-section {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.social-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 32rpx;
|
||||
margin-bottom: 8rpx;
|
||||
display: block;
|
||||
|
||||
&.liked {
|
||||
animation: heartbeat 0.6s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-count {
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
margin-bottom: 4rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes heartbeat {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.2); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
/* 评论区域 */
|
||||
.comments-section {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 40rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.comments-header {
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.comments-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.comments-list {
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.comment-item {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.comment-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
.avatar-text {
|
||||
font-size: 24rpx;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
flex: 1;
|
||||
|
||||
.comment-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.comment-user {
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.comment-time {
|
||||
font-size: 18rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-text {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-comments {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
|
||||
.empty-text {
|
||||
font-size: 24rpx;
|
||||
color: #CCCCCC;
|
||||
}
|
||||
}
|
||||
|
||||
.add-comment {
|
||||
.comment-input-wrapper {
|
||||
position: relative;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
border-radius: 20rpx;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.comment-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding-right: 80rpx;
|
||||
}
|
||||
|
||||
.comment-send {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: #FF8A80;
|
||||
border-radius: 16rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
|
||||
.send-text {
|
||||
font-size: 20rpx;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,559 @@
|
|||
/**
|
||||
* 宠物领养数据管理工具类
|
||||
* 负责领养宠物数据的存储、筛选、搜索等管理
|
||||
*/
|
||||
|
||||
class AdoptionManager {
|
||||
constructor() {
|
||||
this.storageKey = 'adoption_pets'
|
||||
|
||||
// 宠物类型配置
|
||||
this.petTypes = {
|
||||
cat: {
|
||||
name: '猫咪',
|
||||
icon: '🐱',
|
||||
breeds: {
|
||||
'british-shorthair': '英国短毛猫',
|
||||
'american-shorthair': '美国短毛猫',
|
||||
'persian': '波斯猫',
|
||||
'ragdoll': '布偶猫',
|
||||
'siamese': '暹罗猫',
|
||||
'maine-coon': '缅因猫',
|
||||
'scottish-fold': '苏格兰折耳猫',
|
||||
'russian-blue': '俄罗斯蓝猫',
|
||||
'bengal': '孟加拉猫',
|
||||
'mixed': '混血猫',
|
||||
'unknown': '品种不明'
|
||||
}
|
||||
},
|
||||
dog: {
|
||||
name: '狗狗',
|
||||
icon: '🐶',
|
||||
breeds: {
|
||||
'golden-retriever': '金毛寻回犬',
|
||||
'labrador': '拉布拉多',
|
||||
'husky': '哈士奇',
|
||||
'german-shepherd': '德国牧羊犬',
|
||||
'poodle': '贵宾犬',
|
||||
'chihuahua': '吉娃娃',
|
||||
'bulldog': '斗牛犬',
|
||||
'shiba-inu': '柴犬',
|
||||
'corgi': '柯基',
|
||||
'border-collie': '边境牧羊犬',
|
||||
'mixed': '混血犬',
|
||||
'unknown': '品种不明'
|
||||
}
|
||||
},
|
||||
rabbit: {
|
||||
name: '兔子',
|
||||
icon: '🐰',
|
||||
breeds: {
|
||||
'holland-lop': '荷兰垂耳兔',
|
||||
'mini-lop': '迷你垂耳兔',
|
||||
'lionhead': '狮子头兔',
|
||||
'dutch': '荷兰兔',
|
||||
'angora': '安哥拉兔',
|
||||
'mixed': '混血兔',
|
||||
'unknown': '品种不明'
|
||||
}
|
||||
},
|
||||
other: {
|
||||
name: '其他',
|
||||
icon: '🐾',
|
||||
breeds: {
|
||||
'hamster': '仓鼠',
|
||||
'guinea-pig': '豚鼠',
|
||||
'bird': '鸟类',
|
||||
'turtle': '乌龟',
|
||||
'fish': '鱼类',
|
||||
'other': '其他'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 地区数据(简化版三级联动)
|
||||
this.regions = {
|
||||
'beijing': {
|
||||
name: '北京市',
|
||||
cities: {
|
||||
'beijing': {
|
||||
name: '北京市',
|
||||
districts: {
|
||||
'chaoyang': '朝阳区',
|
||||
'haidian': '海淀区',
|
||||
'dongcheng': '东城区',
|
||||
'xicheng': '西城区',
|
||||
'fengtai': '丰台区',
|
||||
'shijingshan': '石景山区'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'shanghai': {
|
||||
name: '上海市',
|
||||
cities: {
|
||||
'shanghai': {
|
||||
name: '上海市',
|
||||
districts: {
|
||||
'huangpu': '黄浦区',
|
||||
'xuhui': '徐汇区',
|
||||
'changning': '长宁区',
|
||||
'jingan': '静安区',
|
||||
'putuo': '普陀区',
|
||||
'hongkou': '虹口区'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'guangdong': {
|
||||
name: '广东省',
|
||||
cities: {
|
||||
'guangzhou': {
|
||||
name: '广州市',
|
||||
districts: {
|
||||
'tianhe': '天河区',
|
||||
'yuexiu': '越秀区',
|
||||
'liwan': '荔湾区',
|
||||
'haizhu': '海珠区',
|
||||
'baiyun': '白云区',
|
||||
'panyu': '番禺区'
|
||||
}
|
||||
},
|
||||
'shenzhen': {
|
||||
name: '深圳市',
|
||||
districts: {
|
||||
'futian': '福田区',
|
||||
'luohu': '罗湖区',
|
||||
'nanshan': '南山区',
|
||||
'yantian': '盐田区',
|
||||
'baoan': '宝安区',
|
||||
'longgang': '龙岗区'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'jiangsu': {
|
||||
name: '江苏省',
|
||||
cities: {
|
||||
'nanjing': {
|
||||
name: '南京市',
|
||||
districts: {
|
||||
'xuanwu': '玄武区',
|
||||
'qinhuai': '秦淮区',
|
||||
'jianye': '建邺区',
|
||||
'gulou': '鼓楼区',
|
||||
'pukou': '浦口区',
|
||||
'qixia': '栖霞区'
|
||||
}
|
||||
},
|
||||
'suzhou': {
|
||||
name: '苏州市',
|
||||
districts: {
|
||||
'gusu': '姑苏区',
|
||||
'wuzhong': '吴中区',
|
||||
'xiangcheng': '相城区',
|
||||
'kunshan': '昆山市',
|
||||
'changshu': '常熟市',
|
||||
'zhangjiagang': '张家港市'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 领养状态
|
||||
this.adoptionStatus = {
|
||||
available: { name: '可领养', color: '#4CAF50', icon: '✅' },
|
||||
reserved: { name: '已预约', color: '#FF9800', icon: '⏰' },
|
||||
adopted: { name: '已领养', color: '#9E9E9E', icon: '❤️' },
|
||||
pending: { name: '审核中', color: '#2196F3', icon: '📋' }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有领养宠物数据
|
||||
* @returns {Array} 领养宠物数组
|
||||
*/
|
||||
getAdoptionPets() {
|
||||
try {
|
||||
let pets = uni.getStorageSync(this.storageKey) || []
|
||||
|
||||
// 如果没有数据,初始化一些测试数据
|
||||
if (pets.length === 0) {
|
||||
pets = this.initializeTestData()
|
||||
uni.setStorageSync(this.storageKey, pets)
|
||||
}
|
||||
|
||||
return pets
|
||||
} catch (error) {
|
||||
console.error('获取领养宠物数据失败:', error)
|
||||
return this.initializeTestData()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化测试数据
|
||||
* @returns {Array} 测试数据数组
|
||||
*/
|
||||
initializeTestData() {
|
||||
const testData = []
|
||||
|
||||
// 猫咪数据
|
||||
testData.push({
|
||||
id: Date.now() + 1,
|
||||
name: '小橘',
|
||||
type: 'cat',
|
||||
breed: 'british-shorthair',
|
||||
age: 2,
|
||||
gender: 'male',
|
||||
photos: ['https://images.unsplash.com/photo-1574158622682-e40e69881006?w=400&h=300&fit=crop', 'https://images.unsplash.com/photo-1592194996308-7b43878e84a6?w=400&h=300&fit=crop'],
|
||||
description: '小橘是一只非常温顺的英国短毛猫,性格亲人,喜欢和人互动。已经完成绝育手术和疫苗接种,身体健康。适合有爱心的家庭领养,希望能给它一个温暖的家。',
|
||||
personality: ['温顺', '亲人', '安静', '乖巧'],
|
||||
health: '健康良好,已绝育,疫苗齐全',
|
||||
location: {
|
||||
province: 'beijing',
|
||||
city: 'beijing',
|
||||
district: 'chaoyang',
|
||||
address: '朝阳区宠物救助中心'
|
||||
},
|
||||
status: 'available',
|
||||
requirements: [
|
||||
'有稳定收入',
|
||||
'有养猫经验',
|
||||
'家中无其他宠物',
|
||||
'同意定期回访'
|
||||
],
|
||||
contact: {
|
||||
name: '北京爱心救助站',
|
||||
phone: '138****1234',
|
||||
wechat: 'rescue_station_bj',
|
||||
type: 'organization'
|
||||
},
|
||||
publishTime: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString()
|
||||
})
|
||||
|
||||
testData.push({
|
||||
id: Date.now() + 2,
|
||||
name: '小白',
|
||||
type: 'dog',
|
||||
breed: 'golden-retriever',
|
||||
age: 1,
|
||||
gender: 'female',
|
||||
photos: ['/static/dog1.jpg', '/static/dog2.jpg'],
|
||||
description: '小白是一只活泼可爱的金毛幼犬,非常聪明,喜欢和小朋友玩耍。',
|
||||
personality: ['活泼', '聪明', '友善'],
|
||||
health: '健康良好,疫苗接种中',
|
||||
location: {
|
||||
province: 'shanghai',
|
||||
city: 'shanghai',
|
||||
district: 'xuhui',
|
||||
address: '徐汇区某某宠物医院'
|
||||
},
|
||||
status: 'available',
|
||||
requirements: [
|
||||
'有足够空间',
|
||||
'每天遛狗',
|
||||
'有耐心训练',
|
||||
'定期体检'
|
||||
],
|
||||
contact: {
|
||||
name: '张医生',
|
||||
phone: '139****5678',
|
||||
wechat: 'dr_zhang',
|
||||
type: 'individual'
|
||||
},
|
||||
publishTime: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
views: 89,
|
||||
favorites: 12
|
||||
})
|
||||
|
||||
testData.push({
|
||||
id: Date.now() + 3,
|
||||
name: '花花',
|
||||
type: 'cat',
|
||||
breed: 'ragdoll',
|
||||
age: 3,
|
||||
gender: 'female',
|
||||
photos: ['/static/cat4.jpg'],
|
||||
description: '花花是一只美丽的布偶猫,性格温和,适合有经验的铲屎官。',
|
||||
personality: ['温和', '优雅', '独立'],
|
||||
health: '健康良好,已绝育',
|
||||
location: {
|
||||
province: 'guangdong',
|
||||
city: 'guangzhou',
|
||||
district: 'tianhe',
|
||||
address: '天河区个人救助'
|
||||
},
|
||||
status: 'reserved',
|
||||
requirements: [
|
||||
'有养猫经验',
|
||||
'家庭环境稳定',
|
||||
'经济条件良好',
|
||||
'同意家访'
|
||||
],
|
||||
contact: {
|
||||
name: '李女士',
|
||||
phone: '137****9012',
|
||||
wechat: 'cat_lover_li',
|
||||
type: 'individual'
|
||||
},
|
||||
publishTime: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
views: 234,
|
||||
favorites: 45
|
||||
})
|
||||
|
||||
testData.push({
|
||||
id: Date.now() + 4,
|
||||
name: '豆豆',
|
||||
type: 'rabbit',
|
||||
breed: 'holland-lop',
|
||||
age: 1,
|
||||
gender: 'male',
|
||||
photos: ['/static/rabbit1.jpg', '/static/rabbit2.jpg'],
|
||||
description: '豆豆是一只可爱的荷兰垂耳兔,很亲人,适合新手饲养。',
|
||||
personality: ['可爱', '亲人', '安静'],
|
||||
health: '健康良好',
|
||||
location: {
|
||||
province: 'jiangsu',
|
||||
city: 'nanjing',
|
||||
district: 'xuanwu',
|
||||
address: '玄武区小动物救助中心'
|
||||
},
|
||||
status: 'available',
|
||||
requirements: [
|
||||
'了解兔子习性',
|
||||
'提供合适笼具',
|
||||
'定期清洁',
|
||||
'适当运动空间'
|
||||
],
|
||||
contact: {
|
||||
name: '小动物救助中心',
|
||||
phone: '025****3456',
|
||||
wechat: 'animal_rescue_nj',
|
||||
type: 'organization'
|
||||
},
|
||||
publishTime: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
views: 67,
|
||||
favorites: 8
|
||||
})
|
||||
|
||||
testData.push({
|
||||
id: Date.now() + 5,
|
||||
name: '黑黑',
|
||||
type: 'cat',
|
||||
breed: 'mixed',
|
||||
age: 4,
|
||||
gender: 'male',
|
||||
photos: ['/static/cat5.jpg'],
|
||||
description: '黑黑是一只成年混血猫,性格稳重,已经完全社会化。',
|
||||
personality: ['稳重', '独立', '温顺'],
|
||||
health: '健康良好,已绝育',
|
||||
location: {
|
||||
province: 'guangdong',
|
||||
city: 'shenzhen',
|
||||
district: 'nanshan',
|
||||
address: '南山区流浪动物救助'
|
||||
},
|
||||
status: 'adopted',
|
||||
requirements: [
|
||||
'有养猫经验',
|
||||
'室内饲养',
|
||||
'定期体检',
|
||||
'终生负责'
|
||||
],
|
||||
contact: {
|
||||
name: '深圳流浪动物救助',
|
||||
phone: '0755****7890',
|
||||
wechat: 'sz_stray_rescue',
|
||||
type: 'organization'
|
||||
},
|
||||
publishTime: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
views: 178,
|
||||
favorites: 34
|
||||
})
|
||||
|
||||
return testData
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索宠物
|
||||
* @param {string} keyword 关键词
|
||||
* @param {Array} pets 宠物数组
|
||||
* @returns {Array} 搜索结果
|
||||
*/
|
||||
searchPets(keyword, pets = null) {
|
||||
if (!pets) {
|
||||
pets = this.getAdoptionPets()
|
||||
}
|
||||
|
||||
if (!keyword) return pets
|
||||
|
||||
const lowerKeyword = keyword.toLowerCase()
|
||||
return pets.filter(pet => {
|
||||
return pet.name.toLowerCase().includes(lowerKeyword) ||
|
||||
pet.description.toLowerCase().includes(lowerKeyword) ||
|
||||
this.getPetTypeName(pet.type).includes(keyword) ||
|
||||
this.getPetBreedName(pet.type, pet.breed).includes(keyword) ||
|
||||
pet.personality.some(trait => trait.includes(keyword))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 筛选宠物
|
||||
* @param {Object} filters 筛选条件
|
||||
* @param {Array} pets 宠物数组
|
||||
* @returns {Array} 筛选结果
|
||||
*/
|
||||
filterPets(filters, pets = null) {
|
||||
if (!pets) {
|
||||
pets = this.getAdoptionPets()
|
||||
}
|
||||
|
||||
return pets.filter(pet => {
|
||||
// 宠物类型筛选
|
||||
if (filters.type && pet.type !== filters.type) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 品种筛选
|
||||
if (filters.breed && pet.breed !== filters.breed) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 地区筛选
|
||||
if (filters.province && pet.location.province !== filters.province) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (filters.city && pet.location.city !== filters.city) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (filters.district && pet.location.district !== filters.district) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (filters.status && pet.status !== filters.status) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 性别筛选
|
||||
if (filters.gender && pet.gender !== filters.gender) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 年龄筛选
|
||||
if (filters.ageRange) {
|
||||
const [minAge, maxAge] = filters.ageRange
|
||||
if (pet.age < minAge || pet.age > maxAge) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宠物类型名称
|
||||
* @param {string} type 类型代码
|
||||
* @returns {string} 类型名称
|
||||
*/
|
||||
getPetTypeName(type) {
|
||||
return this.petTypes[type]?.name || '未知类型'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宠物品种名称
|
||||
* @param {string} type 类型代码
|
||||
* @param {string} breed 品种代码
|
||||
* @returns {string} 品种名称
|
||||
*/
|
||||
getPetBreedName(type, breed) {
|
||||
return this.petTypes[type]?.breeds[breed] || '未知品种'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地区名称
|
||||
* @param {string} province 省份代码
|
||||
* @param {string} city 城市代码
|
||||
* @param {string} district 区县代码
|
||||
* @returns {string} 地区名称
|
||||
*/
|
||||
getLocationName(province, city = null, district = null) {
|
||||
let locationName = this.regions[province]?.name || province
|
||||
|
||||
if (city) {
|
||||
const cityName = this.regions[province]?.cities[city]?.name
|
||||
if (cityName) {
|
||||
locationName += ' ' + cityName
|
||||
}
|
||||
}
|
||||
|
||||
if (district) {
|
||||
const districtName = this.regions[province]?.cities[city]?.districts[district]
|
||||
if (districtName) {
|
||||
locationName += ' ' + districtName
|
||||
}
|
||||
}
|
||||
|
||||
return locationName
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态信息
|
||||
* @param {string} status 状态代码
|
||||
* @returns {Object} 状态信息
|
||||
*/
|
||||
getStatusInfo(status) {
|
||||
return this.adoptionStatus[status] || {
|
||||
name: '未知状态',
|
||||
color: '#999999',
|
||||
icon: '❓'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加浏览量
|
||||
* @param {string} petId 宠物ID
|
||||
*/
|
||||
incrementViews(petId) {
|
||||
try {
|
||||
const pets = this.getAdoptionPets()
|
||||
const petIndex = pets.findIndex(pet => pet.id == petId)
|
||||
|
||||
if (petIndex !== -1) {
|
||||
pets[petIndex].views += 1
|
||||
uni.setStorageSync(this.storageKey, pets)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('增加浏览量失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换收藏状态
|
||||
* @param {string} petId 宠物ID
|
||||
* @param {boolean} isFavorite 是否收藏
|
||||
*/
|
||||
toggleFavorite(petId, isFavorite) {
|
||||
try {
|
||||
const pets = this.getAdoptionPets()
|
||||
const petIndex = pets.findIndex(pet => pet.id == petId)
|
||||
|
||||
if (petIndex !== -1) {
|
||||
if (isFavorite) {
|
||||
pets[petIndex].favorites += 1
|
||||
} else {
|
||||
pets[petIndex].favorites = Math.max(0, pets[petIndex].favorites - 1)
|
||||
}
|
||||
uni.setStorageSync(this.storageKey, pets)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('切换收藏状态失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new AdoptionManager()
|
||||
|
|
@ -0,0 +1,478 @@
|
|||
/**
|
||||
* 宠物记录管理工具类
|
||||
* 负责记录数据的存储、分类、社交功能等管理
|
||||
*/
|
||||
|
||||
class RecordManager {
|
||||
constructor() {
|
||||
this.storageKey = 'pet_records'
|
||||
this.socialDataKey = 'pet_records_social'
|
||||
|
||||
// 记录分类配置
|
||||
this.categories = {
|
||||
// 一级分类
|
||||
health: {
|
||||
name: '健康',
|
||||
icon: '🏥',
|
||||
color: '#4CAF50',
|
||||
subCategories: {
|
||||
medical: { name: '就医记录', icon: '🏥' },
|
||||
checkup: { name: '体检记录', icon: '🔍' },
|
||||
vaccine: { name: '疫苗接种', icon: '💉' },
|
||||
weight: { name: '体重记录', icon: '⚖️' },
|
||||
symptom: { name: '异常症状', icon: '⚠️' },
|
||||
medication: { name: '用药记录', icon: '💊' }
|
||||
}
|
||||
},
|
||||
care: {
|
||||
name: '护理',
|
||||
icon: '🛁',
|
||||
color: '#2196F3',
|
||||
subCategories: {
|
||||
grooming: { name: '洗护美容', icon: '🛁' },
|
||||
cleaning: { name: '清洁护理', icon: '🧽' },
|
||||
nail: { name: '修剪指甲', icon: '✂️' },
|
||||
dental: { name: '口腔护理', icon: '🦷' },
|
||||
ear: { name: '耳部清洁', icon: '👂' },
|
||||
eye: { name: '眼部护理', icon: '👁️' }
|
||||
}
|
||||
},
|
||||
behavior: {
|
||||
name: '行为',
|
||||
icon: '🎾',
|
||||
color: '#FF9800',
|
||||
subCategories: {
|
||||
training: { name: '训练记录', icon: '🎯' },
|
||||
play: { name: '游戏互动', icon: '🎾' },
|
||||
social: { name: '社交活动', icon: '👥' },
|
||||
habit: { name: '习惯养成', icon: '📝' },
|
||||
milestone: { name: '成长里程碑', icon: '🏆' },
|
||||
mood: { name: '情绪状态', icon: '😊' }
|
||||
}
|
||||
},
|
||||
daily: {
|
||||
name: '日常',
|
||||
icon: '📝',
|
||||
color: '#9C27B0',
|
||||
subCategories: {
|
||||
feeding: { name: '喂食记录', icon: '🍽️' },
|
||||
sleep: { name: '睡眠记录', icon: '😴' },
|
||||
exercise: { name: '运动记录', icon: '🏃' },
|
||||
photo: { name: '拍照记录', icon: '📷' },
|
||||
note: { name: '随手记', icon: '📝' },
|
||||
weather: { name: '天气记录', icon: '🌤️' }
|
||||
}
|
||||
},
|
||||
expense: {
|
||||
name: '消费',
|
||||
icon: '💰',
|
||||
color: '#F44336',
|
||||
subCategories: {
|
||||
food: { name: '食物用品', icon: '🍽️' },
|
||||
toy: { name: '玩具用品', icon: '🧸' },
|
||||
medical: { name: '医疗费用', icon: '🏥' },
|
||||
grooming: { name: '美容费用', icon: '✂️' },
|
||||
insurance: { name: '保险费用', icon: '🛡️' },
|
||||
other: { name: '其他消费', icon: '💰' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宠物的所有记录
|
||||
* @param {string} petId 宠物ID
|
||||
* @returns {Array} 记录数组
|
||||
*/
|
||||
getRecords(petId) {
|
||||
try {
|
||||
const allRecords = uni.getStorageSync(this.storageKey) || {}
|
||||
let records = allRecords[petId] || []
|
||||
|
||||
// 如果没有数据,初始化一些测试数据
|
||||
if (records.length === 0) {
|
||||
records = this.initializeTestData(petId)
|
||||
allRecords[petId] = records
|
||||
uni.setStorageSync(this.storageKey, allRecords)
|
||||
}
|
||||
|
||||
return records
|
||||
} catch (error) {
|
||||
console.error('获取记录失败:', error)
|
||||
return this.initializeTestData(petId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化测试数据
|
||||
* @param {string} petId 宠物ID
|
||||
* @returns {Array} 测试数据数组
|
||||
*/
|
||||
initializeTestData(petId) {
|
||||
const now = new Date()
|
||||
const testData = []
|
||||
|
||||
// 健康记录
|
||||
testData.push({
|
||||
id: Date.now() + 1,
|
||||
petId: petId,
|
||||
category: 'health',
|
||||
subCategory: 'checkup',
|
||||
title: '年度体检',
|
||||
content: '带小橘去宠物医院做年度体检,医生说各项指标都很正常,身体很健康!',
|
||||
recordTime: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
photos: ['/static/checkup1.jpg', '/static/checkup2.jpg'],
|
||||
tags: ['体检', '健康', '正常'],
|
||||
location: '宠物医院',
|
||||
weather: '晴天',
|
||||
mood: 'happy',
|
||||
shareLevel: 'family',
|
||||
createTime: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
updateTime: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString()
|
||||
})
|
||||
|
||||
// 护理记录
|
||||
testData.push({
|
||||
id: Date.now() + 2,
|
||||
petId: petId,
|
||||
category: 'care',
|
||||
subCategory: 'grooming',
|
||||
title: '洗澡美容',
|
||||
content: '给小橘洗澡和修剪毛发,全程很乖很配合,洗完后毛毛很蓬松很香!',
|
||||
recordTime: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
photos: ['/static/grooming1.jpg'],
|
||||
tags: ['洗澡', '美容', '乖巧'],
|
||||
location: '家里',
|
||||
weather: '阴天',
|
||||
mood: 'calm',
|
||||
shareLevel: 'family',
|
||||
createTime: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
updateTime: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000).toISOString()
|
||||
})
|
||||
|
||||
// 行为记录
|
||||
testData.push({
|
||||
id: Date.now() + 3,
|
||||
petId: petId,
|
||||
category: 'behavior',
|
||||
subCategory: 'milestone',
|
||||
title: '第一次用猫砂',
|
||||
content: '小橘第一次学会用猫砂盆,真是个聪明的小家伙!这是一个重要的成长里程碑。',
|
||||
recordTime: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
photos: [],
|
||||
tags: ['第一次', '猫砂', '聪明'],
|
||||
location: '家里',
|
||||
weather: '晴天',
|
||||
mood: 'proud',
|
||||
shareLevel: 'public',
|
||||
createTime: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
updateTime: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString()
|
||||
})
|
||||
|
||||
// 日常记录
|
||||
testData.push({
|
||||
id: Date.now() + 4,
|
||||
petId: petId,
|
||||
category: 'daily',
|
||||
subCategory: 'note',
|
||||
title: '今天很活泼',
|
||||
content: '小橘今天特别活泼,一直在客厅里跑来跑去,看起来心情很好!还主动来找我玩。',
|
||||
recordTime: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
photos: ['/static/active1.jpg', '/static/active2.jpg', '/static/active3.jpg'],
|
||||
tags: ['活泼', '开心', '互动'],
|
||||
location: '家里',
|
||||
weather: '晴天',
|
||||
mood: 'excited',
|
||||
shareLevel: 'family',
|
||||
createTime: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
updateTime: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000).toISOString()
|
||||
})
|
||||
|
||||
// 消费记录
|
||||
testData.push({
|
||||
id: Date.now() + 5,
|
||||
petId: petId,
|
||||
category: 'expense',
|
||||
subCategory: 'food',
|
||||
title: '购买猫粮和用品',
|
||||
content: '购买了新的猫粮、猫砂和一些玩具,希望小橘会喜欢。',
|
||||
recordTime: new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
photos: ['/static/shopping1.jpg'],
|
||||
tags: ['猫粮', '猫砂', '玩具'],
|
||||
location: '宠物用品店',
|
||||
weather: '多云',
|
||||
mood: 'happy',
|
||||
shareLevel: 'private',
|
||||
amount: 268,
|
||||
store: '宠物用品店',
|
||||
createTime: new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
updateTime: new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString()
|
||||
})
|
||||
|
||||
return testData
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加记录
|
||||
* @param {string} petId 宠物ID
|
||||
* @param {Object} record 记录数据
|
||||
*/
|
||||
addRecord(petId, record) {
|
||||
try {
|
||||
const allRecords = uni.getStorageSync(this.storageKey) || {}
|
||||
if (!allRecords[petId]) {
|
||||
allRecords[petId] = []
|
||||
}
|
||||
|
||||
const newRecord = {
|
||||
id: Date.now(),
|
||||
petId: petId,
|
||||
category: record.category,
|
||||
subCategory: record.subCategory,
|
||||
title: record.title,
|
||||
content: record.content,
|
||||
recordTime: record.recordTime || new Date().toISOString(),
|
||||
photos: record.photos || [],
|
||||
tags: record.tags || [],
|
||||
location: record.location || '',
|
||||
weather: record.weather || '',
|
||||
mood: record.mood || '',
|
||||
shareLevel: record.shareLevel || 'family',
|
||||
amount: record.amount || 0,
|
||||
store: record.store || '',
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString()
|
||||
}
|
||||
|
||||
allRecords[petId].push(newRecord)
|
||||
allRecords[petId].sort((a, b) => new Date(b.recordTime) - new Date(a.recordTime))
|
||||
|
||||
uni.setStorageSync(this.storageKey, allRecords)
|
||||
|
||||
// 初始化社交数据
|
||||
this.initSocialData(newRecord.id)
|
||||
|
||||
return newRecord
|
||||
} catch (error) {
|
||||
console.error('添加记录失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取记录的社交数据
|
||||
* @param {string} recordId 记录ID
|
||||
* @returns {Object} 社交数据
|
||||
*/
|
||||
getSocialData(recordId) {
|
||||
try {
|
||||
const allSocialData = uni.getStorageSync(this.socialDataKey) || {}
|
||||
return allSocialData[recordId] || {
|
||||
likes: 0,
|
||||
views: 0,
|
||||
comments: [],
|
||||
likedBy: []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取社交数据失败:', error)
|
||||
return {
|
||||
likes: 0,
|
||||
views: 0,
|
||||
comments: [],
|
||||
likedBy: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化社交数据
|
||||
* @param {string} recordId 记录ID
|
||||
*/
|
||||
initSocialData(recordId) {
|
||||
try {
|
||||
const allSocialData = uni.getStorageSync(this.socialDataKey) || {}
|
||||
if (!allSocialData[recordId]) {
|
||||
allSocialData[recordId] = {
|
||||
likes: Math.floor(Math.random() * 10), // 模拟点赞数
|
||||
views: Math.floor(Math.random() * 50) + 10, // 模拟浏览数
|
||||
comments: this.generateMockComments(), // 模拟评论
|
||||
likedBy: []
|
||||
}
|
||||
uni.setStorageSync(this.socialDataKey, allSocialData)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化社交数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成模拟评论
|
||||
* @returns {Array} 评论数组
|
||||
*/
|
||||
generateMockComments() {
|
||||
const comments = [
|
||||
{ id: 1, user: '爱宠达人', content: '好可爱啊!', time: '2小时前' },
|
||||
{ id: 2, user: '猫咪专家', content: '看起来很健康呢', time: '1天前' },
|
||||
{ id: 3, user: '宠物医生', content: '定期体检很重要', time: '2天前' }
|
||||
]
|
||||
|
||||
// 随机返回0-3条评论
|
||||
const count = Math.floor(Math.random() * 4)
|
||||
return comments.slice(0, count)
|
||||
}
|
||||
|
||||
/**
|
||||
* 点赞记录
|
||||
* @param {string} recordId 记录ID
|
||||
* @param {string} userId 用户ID
|
||||
*/
|
||||
likeRecord(recordId, userId = 'current_user') {
|
||||
try {
|
||||
const allSocialData = uni.getStorageSync(this.socialDataKey) || {}
|
||||
if (!allSocialData[recordId]) {
|
||||
this.initSocialData(recordId)
|
||||
allSocialData[recordId] = this.getSocialData(recordId)
|
||||
}
|
||||
|
||||
const socialData = allSocialData[recordId]
|
||||
const likedIndex = socialData.likedBy.indexOf(userId)
|
||||
|
||||
if (likedIndex === -1) {
|
||||
// 点赞
|
||||
socialData.likes += 1
|
||||
socialData.likedBy.push(userId)
|
||||
} else {
|
||||
// 取消点赞
|
||||
socialData.likes -= 1
|
||||
socialData.likedBy.splice(likedIndex, 1)
|
||||
}
|
||||
|
||||
uni.setStorageSync(this.socialDataKey, allSocialData)
|
||||
return socialData
|
||||
} catch (error) {
|
||||
console.error('点赞失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加浏览量
|
||||
* @param {string} recordId 记录ID
|
||||
*/
|
||||
incrementViews(recordId) {
|
||||
try {
|
||||
const allSocialData = uni.getStorageSync(this.socialDataKey) || {}
|
||||
if (!allSocialData[recordId]) {
|
||||
this.initSocialData(recordId)
|
||||
allSocialData[recordId] = this.getSocialData(recordId)
|
||||
}
|
||||
|
||||
allSocialData[recordId].views += 1
|
||||
uni.setStorageSync(this.socialDataKey, allSocialData)
|
||||
} catch (error) {
|
||||
console.error('增加浏览量失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加评论
|
||||
* @param {string} recordId 记录ID
|
||||
* @param {string} content 评论内容
|
||||
* @param {string} user 用户名
|
||||
*/
|
||||
addComment(recordId, content, user = '我') {
|
||||
try {
|
||||
const allSocialData = uni.getStorageSync(this.socialDataKey) || {}
|
||||
if (!allSocialData[recordId]) {
|
||||
this.initSocialData(recordId)
|
||||
allSocialData[recordId] = this.getSocialData(recordId)
|
||||
}
|
||||
|
||||
const newComment = {
|
||||
id: Date.now(),
|
||||
user: user,
|
||||
content: content,
|
||||
time: '刚刚'
|
||||
}
|
||||
|
||||
allSocialData[recordId].comments.unshift(newComment)
|
||||
uni.setStorageSync(this.socialDataKey, allSocialData)
|
||||
|
||||
return newComment
|
||||
} catch (error) {
|
||||
console.error('添加评论失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类信息
|
||||
* @param {string} category 分类
|
||||
* @param {string} subCategory 子分类
|
||||
* @returns {Object} 分类信息
|
||||
*/
|
||||
getCategoryInfo(category, subCategory = null) {
|
||||
const categoryInfo = this.categories[category]
|
||||
if (!categoryInfo) {
|
||||
return { name: '未知分类', icon: '📝', color: '#999999' }
|
||||
}
|
||||
|
||||
if (subCategory && categoryInfo.subCategories) {
|
||||
const subCategoryInfo = categoryInfo.subCategories[subCategory]
|
||||
if (subCategoryInfo) {
|
||||
return {
|
||||
name: subCategoryInfo.name,
|
||||
icon: subCategoryInfo.icon,
|
||||
color: categoryInfo.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: categoryInfo.name,
|
||||
icon: categoryInfo.icon,
|
||||
color: categoryInfo.color
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索记录
|
||||
* @param {string} petId 宠物ID
|
||||
* @param {string} keyword 关键词
|
||||
* @returns {Array} 搜索结果
|
||||
*/
|
||||
searchRecords(petId, keyword) {
|
||||
const records = this.getRecords(petId)
|
||||
if (!keyword) return records
|
||||
|
||||
const lowerKeyword = keyword.toLowerCase()
|
||||
return records.filter(record => {
|
||||
return record.title.toLowerCase().includes(lowerKeyword) ||
|
||||
record.content.toLowerCase().includes(lowerKeyword) ||
|
||||
record.tags.some(tag => tag.toLowerCase().includes(lowerKeyword))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 按分类筛选记录
|
||||
* @param {string} petId 宠物ID
|
||||
* @param {string} category 一级分类
|
||||
* @param {string} subCategory 二级分类
|
||||
* @returns {Array} 筛选结果
|
||||
*/
|
||||
filterRecords(petId, category = null, subCategory = null) {
|
||||
const records = this.getRecords(petId)
|
||||
|
||||
if (!category) return records
|
||||
|
||||
return records.filter(record => {
|
||||
if (subCategory) {
|
||||
return record.category === category && record.subCategory === subCategory
|
||||
} else {
|
||||
return record.category === category
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default new RecordManager()
|
||||
Loading…
Reference in New Issue