1
This commit is contained in:
@@ -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>
|
||||
+1122
-219
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>
|
||||
|
||||
|
||||
+961
-549
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>
|
||||
Reference in New Issue
Block a user