754 lines
15 KiB
Vue
754 lines
15 KiB
Vue
<template>
|
|
<view class="adoption-detail-container page-container-with-bg">
|
|
<!-- 宠物图片轮播 -->
|
|
<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>
|
|
|
|
<!-- 宠物基本信息 -->
|
|
<view class="pet-basic-info">
|
|
<view class="pet-header">
|
|
<text class="pet-name">{{ pet.name }}</text>
|
|
</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>
|
|
// 简化的领养管理器 - 从 utils/adoptionManager.js 移入
|
|
const adoptionManager = {
|
|
storageKey: 'adoption_pets',
|
|
|
|
getAdoptionPets() {
|
|
try {
|
|
return uni.getStorageSync(this.storageKey) || []
|
|
} catch (error) {
|
|
console.error('获取领养宠物数据失败:', error)
|
|
return []
|
|
}
|
|
},
|
|
|
|
getPetById(id) {
|
|
const pets = this.getAdoptionPets()
|
|
return pets.find(pet => pet.id == id)
|
|
},
|
|
|
|
getPetTypeName(type) {
|
|
const types = {
|
|
cat: '猫咪',
|
|
dog: '狗狗',
|
|
rabbit: '兔子',
|
|
other: '其他'
|
|
}
|
|
return types[type] || '未知类型'
|
|
},
|
|
|
|
getPetBreedName(type, breed) {
|
|
const breeds = {
|
|
cat: {
|
|
'british-shorthair': '英国短毛猫',
|
|
'american-shorthair': '美国短毛猫',
|
|
'persian': '波斯猫',
|
|
'ragdoll': '布偶猫',
|
|
'siamese': '暹罗猫',
|
|
'mixed': '混血猫'
|
|
},
|
|
dog: {
|
|
'golden-retriever': '金毛寻回犬',
|
|
'labrador': '拉布拉多',
|
|
'husky': '哈士奇',
|
|
'corgi': '柯基',
|
|
'shiba-inu': '柴犬',
|
|
'mixed': '混血犬'
|
|
}
|
|
}
|
|
return breeds[type]?.[breed] || '未知品种'
|
|
},
|
|
|
|
getLocationName(province, city, district) {
|
|
const regions = {
|
|
'beijing': '北京市',
|
|
'shanghai': '上海市',
|
|
'guangdong': '广东省',
|
|
'jiangsu': '江苏省'
|
|
}
|
|
return regions[province] || province
|
|
},
|
|
|
|
getStatusInfo(status) {
|
|
const statusMap = {
|
|
available: { name: '可领养', color: '#4CAF50', icon: '✅' },
|
|
reserved: { name: '已预约', color: '#FF9800', icon: '⏰' },
|
|
adopted: { name: '已领养', color: '#9E9E9E', icon: '❤️' },
|
|
pending: { name: '审核中', color: '#2196F3', icon: '📋' }
|
|
}
|
|
return statusMap[status] || { name: '未知状态', color: '#999999', icon: '❓' }
|
|
}
|
|
}
|
|
|
|
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
|
|
})
|
|
},
|
|
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/* 宠物基本信息 */
|
|
.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 {
|
|
margin-bottom: 16rpx;
|
|
|
|
.pet-name {
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
}
|
|
}
|
|
|
|
.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>
|