1
This commit is contained in:
@@ -0,0 +1,902 @@
|
||||
<template>
|
||||
<view class="my-adoption-container">
|
||||
<!-- 统计概览卡片 -->
|
||||
<view class="stats-overview-card">
|
||||
<view class="overview-header">
|
||||
<view class="header-info">
|
||||
<text class="header-title">我的领养</text>
|
||||
<text class="header-desc">管理我的领养信息和申请记录</text>
|
||||
</view>
|
||||
<view class="header-icon">
|
||||
<text class="icon-text">🏠</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="stats-grid">
|
||||
<view class="stat-item" @click="navigateTo('/pages/adoption/my-published')">
|
||||
<view class="stat-number">{{ publishedCount }}</view>
|
||||
<view class="stat-label">已发布</view>
|
||||
<view class="stat-icon">📝</view>
|
||||
</view>
|
||||
<view class="stat-item" @click="navigateTo('/pages/adoption/my-applications')">
|
||||
<view class="stat-number">{{ applicationCount }}</view>
|
||||
<view class="stat-label">已申请</view>
|
||||
<view class="stat-icon">📋</view>
|
||||
</view>
|
||||
<view class="stat-item" @click="showSuccessStories">
|
||||
<view class="stat-number">{{ successCount }}</view>
|
||||
<view class="stat-label">成功领养</view>
|
||||
<view class="stat-icon">❤️</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快速操作卡片 -->
|
||||
<view class="quick-actions-card">
|
||||
<view class="card-header">
|
||||
<text class="card-title">快速操作</text>
|
||||
</view>
|
||||
<view class="actions-grid">
|
||||
<view class="action-item" @click="navigateTo('/pages/adoption/publish')">
|
||||
<view class="action-icon">➕</view>
|
||||
<text class="action-text">发布领养</text>
|
||||
<text class="action-desc">发布新的领养信息</text>
|
||||
</view>
|
||||
<view class="action-item" @click="navigateTo('/pages/adoption/adoption')">
|
||||
<view class="action-icon">🔍</view>
|
||||
<text class="action-text">浏览领养</text>
|
||||
<text class="action-desc">查看可领养宠物</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近发布卡片 -->
|
||||
<view class="recent-published-card" v-if="recentPublished.length > 0">
|
||||
<view class="card-header">
|
||||
<text class="card-title">最近发布</text>
|
||||
<view class="header-action" @click="navigateTo('/pages/adoption/my-published')">
|
||||
<text class="action-text">查看全部</text>
|
||||
<text class="action-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="published-list">
|
||||
<view
|
||||
class="published-item"
|
||||
v-for="item in recentPublished.slice(0, 3)"
|
||||
:key="item.id"
|
||||
@click="viewPublishedDetail(item)"
|
||||
>
|
||||
<view class="item-image">
|
||||
<image class="pet-image" :src="item.photos[0]" mode="aspectFill" />
|
||||
<view class="status-badge" :class="item.status">
|
||||
<text class="status-text">{{ getStatusText(item.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-info">
|
||||
<view class="pet-name">{{ item.name }}</view>
|
||||
<view class="pet-meta">
|
||||
<text class="meta-text">{{ item.breed }} · {{ item.gender }}</text>
|
||||
</view>
|
||||
<view class="publish-time">
|
||||
<text class="time-text">{{ formatTime(item.publishTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-stats">
|
||||
<view class="stat-row">
|
||||
<text class="stat-label">申请</text>
|
||||
<text class="stat-value">{{ item.applicationCount || 0 }}</text>
|
||||
</view>
|
||||
<view class="stat-row">
|
||||
<text class="stat-label">浏览</text>
|
||||
<text class="stat-value">{{ item.viewCount || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近申请卡片 -->
|
||||
<view class="recent-applications-card" v-if="recentApplications.length > 0">
|
||||
<view class="card-header">
|
||||
<text class="card-title">最近申请</text>
|
||||
<view class="header-action" @click="navigateTo('/pages/adoption/my-applications')">
|
||||
<text class="action-text">查看全部</text>
|
||||
<text class="action-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="applications-list">
|
||||
<view
|
||||
class="application-item"
|
||||
v-for="item in recentApplications.slice(0, 3)"
|
||||
:key="item.id"
|
||||
@click="viewApplicationDetail(item)"
|
||||
>
|
||||
<view class="item-image">
|
||||
<image class="pet-image" :src="item.petPhoto" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="item-info">
|
||||
<view class="pet-name">{{ item.petName }}</view>
|
||||
<view class="pet-meta">
|
||||
<text class="meta-text">{{ item.petBreed }} · {{ item.petGender }}</text>
|
||||
</view>
|
||||
<view class="application-time">
|
||||
<text class="time-text">{{ formatTime(item.applicationTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-status">
|
||||
<view class="status-badge" :class="item.status">
|
||||
<text class="status-text">{{ getApplicationStatusText(item.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-if="publishedCount === 0 && applicationCount === 0">
|
||||
<view class="empty-icon">🏠</view>
|
||||
<view class="empty-text">还没有领养相关记录</view>
|
||||
<view class="empty-desc">发布领养信息或申请领养可爱的宠物</view>
|
||||
<view class="empty-actions">
|
||||
<view class="empty-action primary" @click="navigateTo('/pages/adoption/publish')">
|
||||
<text class="action-text">发布领养</text>
|
||||
</view>
|
||||
<view class="empty-action" @click="navigateTo('/pages/adoption/adoption')">
|
||||
<text class="action-text">浏览领养</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 帮助提示卡片 -->
|
||||
<view class="help-card">
|
||||
<view class="help-header">
|
||||
<text class="help-icon">💡</text>
|
||||
<text class="help-title">领养小贴士</text>
|
||||
</view>
|
||||
<view class="help-content">
|
||||
<view class="help-item">
|
||||
<text class="help-text">• 发布领养信息时请提供详细的宠物信息和照片</text>
|
||||
</view>
|
||||
<view class="help-item">
|
||||
<text class="help-text">• 申请领养时请如实填写个人信息和养宠经验</text>
|
||||
</view>
|
||||
<view class="help-item">
|
||||
<text class="help-text">• 保持良好的沟通,为宠物找到最合适的家庭</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, onMounted, computed } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'MyAdoptionPage',
|
||||
setup() {
|
||||
// 响应式数据
|
||||
const publishedCount = ref(0)
|
||||
const applicationCount = ref(0)
|
||||
const successCount = ref(0)
|
||||
const recentPublished = ref([])
|
||||
const recentApplications = ref([])
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadAdoptionData()
|
||||
})
|
||||
|
||||
// 方法定义
|
||||
const loadAdoptionData = () => {
|
||||
try {
|
||||
// 加载发布的领养信息
|
||||
const publishedData = uni.getStorageSync('myPublishedAdoptions') || []
|
||||
publishedCount.value = publishedData.length
|
||||
recentPublished.value = publishedData.sort((a, b) =>
|
||||
new Date(b.publishTime) - new Date(a.publishTime)
|
||||
)
|
||||
|
||||
// 加载申请记录
|
||||
const applicationData = uni.getStorageSync('myAdoptionApplications') || []
|
||||
applicationCount.value = applicationData.length
|
||||
recentApplications.value = applicationData.sort((a, b) =>
|
||||
new Date(b.applicationTime) - new Date(a.applicationTime)
|
||||
)
|
||||
|
||||
// 计算成功领养数量
|
||||
const successfulAdoptions = publishedData.filter(item => item.status === 'completed').length +
|
||||
applicationData.filter(item => item.status === 'approved').length
|
||||
successCount.value = successfulAdoptions
|
||||
|
||||
// 如果没有数据,创建一些模拟数据用于展示
|
||||
if (publishedData.length === 0 && applicationData.length === 0) {
|
||||
createMockData()
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载领养数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const createMockData = () => {
|
||||
// 创建模拟发布数据
|
||||
const mockPublished = [
|
||||
{
|
||||
id: 'pub_1',
|
||||
name: '小橘',
|
||||
breed: '橘猫',
|
||||
gender: '公',
|
||||
photos: ['/static/mock-cat1.jpg'],
|
||||
status: 'active',
|
||||
publishTime: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
applicationCount: 3,
|
||||
viewCount: 25
|
||||
}
|
||||
]
|
||||
|
||||
// 创建模拟申请数据
|
||||
const mockApplications = [
|
||||
{
|
||||
id: 'app_1',
|
||||
petName: '小白',
|
||||
petBreed: '英短',
|
||||
petGender: '母',
|
||||
petPhoto: '/static/mock-cat2.jpg',
|
||||
status: 'pending',
|
||||
applicationTime: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString()
|
||||
}
|
||||
]
|
||||
|
||||
uni.setStorageSync('myPublishedAdoptions', mockPublished)
|
||||
uni.setStorageSync('myAdoptionApplications', mockApplications)
|
||||
|
||||
publishedCount.value = mockPublished.length
|
||||
applicationCount.value = mockApplications.length
|
||||
recentPublished.value = mockPublished
|
||||
recentApplications.value = mockApplications
|
||||
}
|
||||
|
||||
const navigateTo = (url) => {
|
||||
uni.navigateTo({
|
||||
url,
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const showSuccessStories = () => {
|
||||
if (successCount.value > 0) {
|
||||
uni.showModal({
|
||||
title: '成功领养',
|
||||
content: `恭喜您!已成功完成 ${successCount.value} 次领养,为宠物们找到了温暖的家。`,
|
||||
showCancel: false
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '暂无成功记录',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const viewPublishedDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/adoption/adoption-detail?id=${item.id}&from=published`,
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const viewApplicationDetail = (item) => {
|
||||
uni.showModal({
|
||||
title: item.petName,
|
||||
content: `申请状态:${getApplicationStatusText(item.status)}\n申请时间:${formatTime(item.applicationTime)}`,
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'active': '招募中',
|
||||
'paused': '已暂停',
|
||||
'completed': '已完成',
|
||||
'cancelled': '已取消'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
const getApplicationStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'pending': '待审核',
|
||||
'approved': '已通过',
|
||||
'rejected': '已拒绝',
|
||||
'cancelled': '已取消'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
const formatTime = (timeString) => {
|
||||
if (!timeString) return ''
|
||||
const date = new Date(timeString)
|
||||
const now = new Date()
|
||||
const diffTime = now - date
|
||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (diffDays === 0) {
|
||||
return '今天'
|
||||
} else if (diffDays === 1) {
|
||||
return '昨天'
|
||||
} else if (diffDays < 7) {
|
||||
return `${diffDays}天前`
|
||||
} else {
|
||||
return date.toLocaleDateString('zh-CN')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
publishedCount,
|
||||
applicationCount,
|
||||
successCount,
|
||||
recentPublished,
|
||||
recentApplications,
|
||||
navigateTo,
|
||||
showSuccessStories,
|
||||
viewPublishedDetail,
|
||||
viewApplicationDetail,
|
||||
getStatusText,
|
||||
getApplicationStatusText,
|
||||
formatTime
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-adoption-container {
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
|
||||
min-height: 100vh;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
/* 通用卡片样式 */
|
||||
.stats-overview-card,
|
||||
.quick-actions-card,
|
||||
.recent-published-card,
|
||||
.recent-applications-card,
|
||||
.help-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
margin: 0 30rpx 24rpx 30rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.card-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.header-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.action-text {
|
||||
font-size: 24rpx;
|
||||
color: #FF8A80;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.action-arrow {
|
||||
font-size: 24rpx;
|
||||
color: #FF8A80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 统计概览卡片 */
|
||||
.stats-overview-card {
|
||||
.overview-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
.header-info {
|
||||
flex: 1;
|
||||
|
||||
.header-title {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.header-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
.icon-text {
|
||||
font-size: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 24rpx;
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 24rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #FF8A80;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 快速操作卡片 */
|
||||
.quick-actions-card {
|
||||
.actions-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20rpx;
|
||||
|
||||
.action-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 32rpx 24rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 48rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.action-desc {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
text-align: center;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 最近发布卡片 */
|
||||
.recent-published-card {
|
||||
.published-list {
|
||||
.published-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
position: relative;
|
||||
margin-right: 20rpx;
|
||||
|
||||
.pet-image {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
position: absolute;
|
||||
top: -8rpx;
|
||||
right: -8rpx;
|
||||
padding: 4rpx 8rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 18rpx;
|
||||
|
||||
&.active {
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.paused {
|
||||
background: #FF9800;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.completed {
|
||||
background: #2196F3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.cancelled {
|
||||
background: #F44336;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 18rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
|
||||
.pet-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.pet-meta {
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.meta-text {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.publish-time {
|
||||
.time-text {
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-stats {
|
||||
text-align: right;
|
||||
|
||||
.stat-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #FF8A80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 最近申请卡片 */
|
||||
.recent-applications-card {
|
||||
.applications-list {
|
||||
.application-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
margin-right: 20rpx;
|
||||
|
||||
.pet-image {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
|
||||
.pet-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.pet-meta {
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.meta-text {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.application-time {
|
||||
.time-text {
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-status {
|
||||
.status-badge {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 20rpx;
|
||||
|
||||
&.pending {
|
||||
background: #FFF3E0;
|
||||
color: #FF9800;
|
||||
border: 1rpx solid #FFE0B2;
|
||||
}
|
||||
|
||||
&.approved {
|
||||
background: #E8F5E8;
|
||||
color: #4CAF50;
|
||||
border: 1rpx solid #C8E6C9;
|
||||
}
|
||||
|
||||
&.rejected {
|
||||
background: #FFEBEE;
|
||||
color: #F44336;
|
||||
border: 1rpx solid #FFCDD2;
|
||||
}
|
||||
|
||||
&.cancelled {
|
||||
background: #F5F5F5;
|
||||
color: #757575;
|
||||
border: 1rpx solid #E0E0E0;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 80rpx 40rpx;
|
||||
margin: 0 30rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 24rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.empty-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
margin-bottom: 40rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.empty-actions {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
justify-content: center;
|
||||
|
||||
.empty-action {
|
||||
padding: 16rpx 32rpx;
|
||||
border-radius: 20rpx;
|
||||
border: 2rpx solid #FF8A80;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.primary {
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
|
||||
.action-text {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.primary) {
|
||||
background: transparent;
|
||||
|
||||
.action-text {
|
||||
color: #FF8A80;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 帮助提示卡片 */
|
||||
.help-card {
|
||||
.help-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.help-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.help-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.help-content {
|
||||
.help-item {
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 375px) {
|
||||
.my-adoption-container {
|
||||
.stats-overview-card,
|
||||
.quick-actions-card,
|
||||
.recent-published-card,
|
||||
.recent-applications-card,
|
||||
.help-card,
|
||||
.empty-state {
|
||||
margin: 0 20rpx 20rpx 20rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
gap: 16rpx;
|
||||
|
||||
.stat-item {
|
||||
padding: 20rpx 12rpx;
|
||||
|
||||
.stat-number {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions-grid {
|
||||
gap: 16rpx;
|
||||
|
||||
.action-item {
|
||||
padding: 24rpx 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20rpx);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.my-adoption-container > view {
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
.my-adoption-container > view:nth-child(1) { animation-delay: 0.1s; }
|
||||
.my-adoption-container > view:nth-child(2) { animation-delay: 0.2s; }
|
||||
.my-adoption-container > view:nth-child(3) { animation-delay: 0.3s; }
|
||||
.my-adoption-container > view:nth-child(4) { animation-delay: 0.4s; }
|
||||
.my-adoption-container > view:nth-child(5) { animation-delay: 0.5s; }
|
||||
.my-adoption-container > view:nth-child(6) { animation-delay: 0.6s; }
|
||||
</style>
|
||||
@@ -0,0 +1,831 @@
|
||||
<template>
|
||||
<view class="my-applications-container">
|
||||
<!-- 统计卡片 -->
|
||||
<view class="stats-card">
|
||||
<view class="stats-grid">
|
||||
<view class="stat-item" :class="{ active: currentFilter === 'all' }" @click="setFilter('all')">
|
||||
<view class="stat-number">{{ totalCount }}</view>
|
||||
<view class="stat-label">全部</view>
|
||||
</view>
|
||||
<view class="stat-item" :class="{ active: currentFilter === 'pending' }" @click="setFilter('pending')">
|
||||
<view class="stat-number">{{ pendingCount }}</view>
|
||||
<view class="stat-label">待审核</view>
|
||||
</view>
|
||||
<view class="stat-item" :class="{ active: currentFilter === 'approved' }" @click="setFilter('approved')">
|
||||
<view class="stat-number">{{ approvedCount }}</view>
|
||||
<view class="stat-label">已通过</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请列表 -->
|
||||
<view class="applications-list" v-if="filteredList.length > 0">
|
||||
<view
|
||||
class="application-item"
|
||||
v-for="item in filteredList"
|
||||
:key="item.id"
|
||||
@click="viewDetail(item)"
|
||||
>
|
||||
<view class="item-image">
|
||||
<image class="pet-image" :src="item.petPhoto || '/static/default-pet.png'" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-header">
|
||||
<view class="pet-name">{{ item.petName }}</view>
|
||||
<view class="status-badge" :class="item.status">
|
||||
<text class="status-text">{{ getStatusText(item.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pet-info">
|
||||
<view class="info-row">
|
||||
<text class="info-text">{{ item.petBreed }} · {{ item.petGender }} · {{ item.petAge }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">发布者:</text>
|
||||
<text class="info-value">{{ item.publisherName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="application-info">
|
||||
<view class="info-row">
|
||||
<text class="info-label">申请时间:</text>
|
||||
<text class="info-value">{{ formatTime(item.applicationTime) }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="item.responseTime">
|
||||
<text class="info-label">回复时间:</text>
|
||||
<text class="info-value">{{ formatTime(item.responseTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="application-message" v-if="item.message">
|
||||
<view class="message-label">申请留言:</view>
|
||||
<view class="message-content">{{ item.message }}</view>
|
||||
</view>
|
||||
<view class="response-message" v-if="item.responseMessage">
|
||||
<view class="message-label">回复消息:</view>
|
||||
<view class="message-content">{{ item.responseMessage }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-actions">
|
||||
<view class="action-button" @click.stop="showActions(item)">
|
||||
<text class="action-icon">⋯</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else>
|
||||
<view class="empty-icon">📋</view>
|
||||
<view class="empty-text">{{ getEmptyText() }}</view>
|
||||
<view class="empty-action" @click="browseAdoptions" v-if="currentFilter === 'all'">
|
||||
<text class="action-text">去看看可领养的宠物</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作菜单 -->
|
||||
<u-action-sheet
|
||||
:show="showActionSheet"
|
||||
:actions="actionList"
|
||||
@close="showActionSheet = false"
|
||||
@select="onActionSelect"
|
||||
></u-action-sheet>
|
||||
|
||||
<!-- 申请详情弹窗 -->
|
||||
<u-modal
|
||||
:show="showDetailModal"
|
||||
:title="currentItem?.petName || '申请详情'"
|
||||
@confirm="closeDetailModal"
|
||||
@cancel="closeDetailModal"
|
||||
:show-cancel-button="false"
|
||||
confirm-text="关闭"
|
||||
>
|
||||
<view class="detail-content" v-if="currentItem">
|
||||
<view class="detail-section">
|
||||
<text class="section-title">宠物信息</text>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">名称:</text>
|
||||
<text class="detail-value">{{ currentItem.petName }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">品种:</text>
|
||||
<text class="detail-value">{{ currentItem.petBreed }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">性别:</text>
|
||||
<text class="detail-value">{{ currentItem.petGender }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">年龄:</text>
|
||||
<text class="detail-value">{{ currentItem.petAge }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-section">
|
||||
<text class="section-title">申请信息</text>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">状态:</text>
|
||||
<text class="detail-value" :class="currentItem.status">{{ getStatusText(currentItem.status) }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">申请时间:</text>
|
||||
<text class="detail-value">{{ formatDateTime(currentItem.applicationTime) }}</text>
|
||||
</view>
|
||||
<view class="detail-row" v-if="currentItem.responseTime">
|
||||
<text class="detail-label">回复时间:</text>
|
||||
<text class="detail-value">{{ formatDateTime(currentItem.responseTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-section" v-if="currentItem.message">
|
||||
<text class="section-title">申请留言</text>
|
||||
<view class="message-box">{{ currentItem.message }}</view>
|
||||
</view>
|
||||
<view class="detail-section" v-if="currentItem.responseMessage">
|
||||
<text class="section-title">回复消息</text>
|
||||
<view class="message-box response">{{ currentItem.responseMessage }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, onMounted, computed } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'MyApplicationsPage',
|
||||
setup() {
|
||||
// 响应式数据
|
||||
const applicationsList = ref([])
|
||||
const currentFilter = ref('all')
|
||||
const showActionSheet = ref(false)
|
||||
const showDetailModal = ref(false)
|
||||
const currentItem = ref(null)
|
||||
|
||||
const actionList = ref([
|
||||
{ name: '查看详情', value: 'detail' },
|
||||
{ name: '联系发布者', value: 'contact' },
|
||||
{ name: '撤销申请', value: 'cancel', color: '#FF5722' }
|
||||
])
|
||||
|
||||
// 计算属性
|
||||
const totalCount = computed(() => applicationsList.value.length)
|
||||
const pendingCount = computed(() => applicationsList.value.filter(item => item.status === 'pending').length)
|
||||
const approvedCount = computed(() => applicationsList.value.filter(item => item.status === 'approved').length)
|
||||
|
||||
const filteredList = computed(() => {
|
||||
if (currentFilter.value === 'all') {
|
||||
return applicationsList.value
|
||||
}
|
||||
return applicationsList.value.filter(item => item.status === currentFilter.value)
|
||||
})
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadApplicationsList()
|
||||
})
|
||||
|
||||
// 方法定义
|
||||
const loadApplicationsList = () => {
|
||||
try {
|
||||
const savedList = uni.getStorageSync('myAdoptionApplications') || []
|
||||
|
||||
// 如果没有数据,创建模拟数据
|
||||
if (savedList.length === 0) {
|
||||
const mockData = [
|
||||
{
|
||||
id: 'app_1',
|
||||
petName: '小白',
|
||||
petBreed: '英短',
|
||||
petGender: '母',
|
||||
petAge: '1岁',
|
||||
petPhoto: '/static/mock-cat2.jpg',
|
||||
publisherName: '爱心铲屎官',
|
||||
status: 'pending',
|
||||
applicationTime: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
message: '我很喜欢猫咪,有3年的养猫经验,家里环境很适合养宠物,希望能给小白一个温暖的家。',
|
||||
responseTime: null,
|
||||
responseMessage: null
|
||||
},
|
||||
{
|
||||
id: 'app_2',
|
||||
petName: '小黑',
|
||||
petBreed: '田园犬',
|
||||
petGender: '公',
|
||||
petAge: '2岁',
|
||||
petPhoto: '/static/mock-dog1.jpg',
|
||||
publisherName: '宠物救助站',
|
||||
status: 'approved',
|
||||
applicationTime: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
message: '我想领养小黑,我有充足的时间照顾它,也有养狗的经验。',
|
||||
responseTime: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
responseMessage: '感谢您的申请!经过审核,我们认为您很适合领养小黑。请联系我们安排见面。'
|
||||
},
|
||||
{
|
||||
id: 'app_3',
|
||||
petName: '小花',
|
||||
petBreed: '三花猫',
|
||||
petGender: '母',
|
||||
petAge: '6个月',
|
||||
petPhoto: '/static/mock-cat3.jpg',
|
||||
publisherName: '个人用户',
|
||||
status: 'rejected',
|
||||
applicationTime: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
message: '希望能领养小花,我会好好照顾它的。',
|
||||
responseTime: new Date(Date.now() - 8 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
responseMessage: '很抱歉,我们已经为小花找到了合适的家庭。感谢您的关注!'
|
||||
}
|
||||
]
|
||||
|
||||
uni.setStorageSync('myAdoptionApplications', mockData)
|
||||
applicationsList.value = mockData
|
||||
} else {
|
||||
applicationsList.value = savedList
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载申请列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const saveApplicationsList = () => {
|
||||
uni.setStorageSync('myAdoptionApplications', applicationsList.value)
|
||||
}
|
||||
|
||||
const setFilter = (filter) => {
|
||||
currentFilter.value = filter
|
||||
}
|
||||
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'pending': '待审核',
|
||||
'approved': '已通过',
|
||||
'rejected': '已拒绝',
|
||||
'cancelled': '已取消'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
const getEmptyText = () => {
|
||||
switch (currentFilter.value) {
|
||||
case 'pending':
|
||||
return '暂无待审核的申请'
|
||||
case 'approved':
|
||||
return '暂无已通过的申请'
|
||||
default:
|
||||
return '还没有申请过领养'
|
||||
}
|
||||
}
|
||||
|
||||
const formatTime = (timeString) => {
|
||||
if (!timeString) return ''
|
||||
const date = new Date(timeString)
|
||||
const now = new Date()
|
||||
const diffTime = now - date
|
||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (diffDays === 0) {
|
||||
return '今天'
|
||||
} else if (diffDays === 1) {
|
||||
return '昨天'
|
||||
} else if (diffDays < 7) {
|
||||
return `${diffDays}天前`
|
||||
} else {
|
||||
return date.toLocaleDateString('zh-CN')
|
||||
}
|
||||
}
|
||||
|
||||
const formatDateTime = (timeString) => {
|
||||
if (!timeString) return ''
|
||||
const date = new Date(timeString)
|
||||
return date.toLocaleString('zh-CN')
|
||||
}
|
||||
|
||||
const viewDetail = (item) => {
|
||||
currentItem.value = item
|
||||
showDetailModal.value = true
|
||||
}
|
||||
|
||||
const closeDetailModal = () => {
|
||||
showDetailModal.value = false
|
||||
currentItem.value = null
|
||||
}
|
||||
|
||||
const showActions = (item) => {
|
||||
currentItem.value = item
|
||||
|
||||
// 根据状态调整操作菜单
|
||||
if (item.status === 'pending') {
|
||||
actionList.value = [
|
||||
{ name: '查看详情', value: 'detail' },
|
||||
{ name: '联系发布者', value: 'contact' },
|
||||
{ name: '撤销申请', value: 'cancel', color: '#FF5722' }
|
||||
]
|
||||
} else {
|
||||
actionList.value = [
|
||||
{ name: '查看详情', value: 'detail' },
|
||||
{ name: '联系发布者', value: 'contact' }
|
||||
]
|
||||
}
|
||||
|
||||
showActionSheet.value = true
|
||||
}
|
||||
|
||||
const onActionSelect = (action) => {
|
||||
switch (action.value) {
|
||||
case 'detail':
|
||||
viewDetail(currentItem.value)
|
||||
break
|
||||
case 'contact':
|
||||
contactPublisher(currentItem.value)
|
||||
break
|
||||
case 'cancel':
|
||||
cancelApplication(currentItem.value)
|
||||
break
|
||||
}
|
||||
showActionSheet.value = false
|
||||
}
|
||||
|
||||
const contactPublisher = (item) => {
|
||||
uni.showModal({
|
||||
title: '联系发布者',
|
||||
content: `发布者:${item.publisherName}\n\n您可以通过以下方式联系:\n• 站内私信\n• 电话联系\n• 微信联系`,
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
|
||||
const cancelApplication = (item) => {
|
||||
uni.showModal({
|
||||
title: '撤销申请',
|
||||
content: '确定要撤销这个领养申请吗?撤销后无法恢复。',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
item.status = 'cancelled'
|
||||
saveApplicationsList()
|
||||
|
||||
uni.showToast({
|
||||
title: '申请已撤销',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const browseAdoptions = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/adoption/adoption',
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
applicationsList,
|
||||
currentFilter,
|
||||
showActionSheet,
|
||||
showDetailModal,
|
||||
currentItem,
|
||||
actionList,
|
||||
totalCount,
|
||||
pendingCount,
|
||||
approvedCount,
|
||||
filteredList,
|
||||
setFilter,
|
||||
getStatusText,
|
||||
getEmptyText,
|
||||
formatTime,
|
||||
formatDateTime,
|
||||
viewDetail,
|
||||
closeDetailModal,
|
||||
showActions,
|
||||
onActionSelect,
|
||||
browseAdoptions
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-applications-container {
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
|
||||
min-height: 100vh;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.stats-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
margin: 0 30rpx 24rpx 30rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 20rpx;
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 24rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
|
||||
.stat-number,
|
||||
.stat-label {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #FF8A80;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 申请列表 */
|
||||
.applications-list {
|
||||
margin: 0 30rpx;
|
||||
|
||||
.application-item {
|
||||
display: flex;
|
||||
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);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.item-image {
|
||||
margin-right: 20rpx;
|
||||
|
||||
.pet-image {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
.pet-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 20rpx;
|
||||
|
||||
&.pending {
|
||||
background: #FFF3E0;
|
||||
color: #FF9800;
|
||||
border: 1rpx solid #FFE0B2;
|
||||
}
|
||||
|
||||
&.approved {
|
||||
background: #E8F5E8;
|
||||
color: #4CAF50;
|
||||
border: 1rpx solid #C8E6C9;
|
||||
}
|
||||
|
||||
&.rejected {
|
||||
background: #FFEBEE;
|
||||
color: #F44336;
|
||||
border: 1rpx solid #FFCDD2;
|
||||
}
|
||||
|
||||
&.cancelled {
|
||||
background: #F5F5F5;
|
||||
color: #757575;
|
||||
border: 1rpx solid #E0E0E0;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pet-info {
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 6rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 22rpx;
|
||||
color: #999999;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.application-info {
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 6rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 22rpx;
|
||||
color: #999999;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.application-message,
|
||||
.response-message {
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.message-label {
|
||||
font-size: 22rpx;
|
||||
color: #999999;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
line-height: 1.5;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
padding: 12rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.response-message {
|
||||
.message-content {
|
||||
background: rgba(76, 175, 80, 0.05);
|
||||
border-left: 4rpx solid #4CAF50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.action-button {
|
||||
padding: 8rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
|
||||
.action-icon {
|
||||
font-size: 24rpx;
|
||||
color: #FF8A80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 80rpx 40rpx;
|
||||
margin: 0 30rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 24rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
margin-bottom: 32rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.empty-action {
|
||||
display: inline-block;
|
||||
padding: 16rpx 32rpx;
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
border-radius: 20rpx;
|
||||
|
||||
.action-text {
|
||||
font-size: 26rpx;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 详情弹窗 */
|
||||
.detail-content {
|
||||
padding: 20rpx 0;
|
||||
|
||||
.detail-section {
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 16rpx;
|
||||
padding-bottom: 8rpx;
|
||||
border-bottom: 2rpx solid rgba(255, 138, 128, 0.2);
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
width: 120rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
|
||||
&.pending {
|
||||
color: #FF9800;
|
||||
}
|
||||
|
||||
&.approved {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
&.rejected {
|
||||
color: #F44336;
|
||||
}
|
||||
|
||||
&.cancelled {
|
||||
color: #757575;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-box {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
line-height: 1.6;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
padding: 16rpx;
|
||||
border-radius: 12rpx;
|
||||
|
||||
&.response {
|
||||
background: rgba(76, 175, 80, 0.05);
|
||||
border-left: 4rpx solid #4CAF50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 375px) {
|
||||
.my-applications-container {
|
||||
.stats-card,
|
||||
.applications-list,
|
||||
.empty-state {
|
||||
margin-left: 20rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
gap: 16rpx;
|
||||
|
||||
.stat-item {
|
||||
padding: 20rpx 12rpx;
|
||||
|
||||
.stat-number {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.application-item {
|
||||
padding: 20rpx;
|
||||
|
||||
.item-image {
|
||||
margin-right: 16rpx;
|
||||
|
||||
.pet-image {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20rpx);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.my-applications-container > view {
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
.application-item {
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* 状态过渡动画 */
|
||||
.status-badge {
|
||||
animation: fadeIn 0.4s ease-out;
|
||||
}
|
||||
|
||||
.action-button:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,852 @@
|
||||
<template>
|
||||
<view class="my-published-container">
|
||||
<!-- 统计卡片 -->
|
||||
<view class="stats-card">
|
||||
<view class="stats-grid">
|
||||
<view class="stat-item" :class="{ active: currentFilter === 'all' }" @click="setFilter('all')">
|
||||
<view class="stat-number">{{ totalCount }}</view>
|
||||
<view class="stat-label">全部</view>
|
||||
</view>
|
||||
<view class="stat-item" :class="{ active: currentFilter === 'active' }" @click="setFilter('active')">
|
||||
<view class="stat-number">{{ activeCount }}</view>
|
||||
<view class="stat-label">招募中</view>
|
||||
</view>
|
||||
<view class="stat-item" :class="{ active: currentFilter === 'completed' }" @click="setFilter('completed')">
|
||||
<view class="stat-number">{{ completedCount }}</view>
|
||||
<view class="stat-label">已完成</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 发布列表 -->
|
||||
<view class="published-list" v-if="filteredList.length > 0">
|
||||
<view
|
||||
class="published-item"
|
||||
v-for="item in filteredList"
|
||||
:key="item.id"
|
||||
@click="viewDetail(item)"
|
||||
>
|
||||
<view class="item-image">
|
||||
<image class="pet-image" :src="item.photos[0] || '/static/default-pet.png'" mode="aspectFill" />
|
||||
<view class="status-badge" :class="item.status">
|
||||
<text class="status-text">{{ getStatusText(item.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-header">
|
||||
<view class="pet-name">{{ item.name }}</view>
|
||||
<view class="item-actions" @click.stop="showActions(item)">
|
||||
<text class="action-icon">⋯</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pet-info">
|
||||
<view class="info-row">
|
||||
<text class="info-label">品种:</text>
|
||||
<text class="info-value">{{ item.breed }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">性别:</text>
|
||||
<text class="info-value">{{ item.gender }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">年龄:</text>
|
||||
<text class="info-value">{{ item.age }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-stats">
|
||||
<view class="stat-group">
|
||||
<text class="stat-icon">👁️</text>
|
||||
<text class="stat-text">{{ item.viewCount || 0 }} 浏览</text>
|
||||
</view>
|
||||
<view class="stat-group">
|
||||
<text class="stat-icon">📝</text>
|
||||
<text class="stat-text">{{ item.applicationCount || 0 }} 申请</text>
|
||||
</view>
|
||||
<view class="stat-group">
|
||||
<text class="stat-icon">🕐</text>
|
||||
<text class="stat-text">{{ formatTime(item.publishTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-description" v-if="item.description">
|
||||
{{ item.description }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else>
|
||||
<view class="empty-icon">📝</view>
|
||||
<view class="empty-text">{{ getEmptyText() }}</view>
|
||||
<view class="empty-action" @click="publishNew" v-if="currentFilter === 'all'">
|
||||
<text class="action-text">发布第一个领养信息</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 浮动发布按钮 -->
|
||||
<view class="fab-button" @click="publishNew">
|
||||
<text class="fab-icon">+</text>
|
||||
</view>
|
||||
|
||||
<!-- 操作菜单 -->
|
||||
<u-action-sheet
|
||||
:show="showActionSheet"
|
||||
:actions="actionList"
|
||||
@close="showActionSheet = false"
|
||||
@select="onActionSelect"
|
||||
></u-action-sheet>
|
||||
|
||||
<!-- 编辑状态弹窗 -->
|
||||
<u-modal
|
||||
:show="showStatusModal"
|
||||
title="修改状态"
|
||||
@confirm="confirmStatusChange"
|
||||
@cancel="showStatusModal = false"
|
||||
>
|
||||
<view class="status-options">
|
||||
<view
|
||||
class="status-option"
|
||||
v-for="status in statusOptions"
|
||||
:key="status.value"
|
||||
:class="{ active: selectedStatus === status.value }"
|
||||
@click="selectStatus(status.value)"
|
||||
>
|
||||
<view class="option-icon" :class="status.value">
|
||||
<text class="icon-text">{{ status.icon }}</text>
|
||||
</view>
|
||||
<view class="option-info">
|
||||
<text class="option-title">{{ status.label }}</text>
|
||||
<text class="option-desc">{{ status.desc }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, onMounted, computed } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'MyPublishedPage',
|
||||
setup() {
|
||||
// 响应式数据
|
||||
const publishedList = ref([])
|
||||
const currentFilter = ref('all')
|
||||
const showActionSheet = ref(false)
|
||||
const showStatusModal = ref(false)
|
||||
const currentItem = ref(null)
|
||||
const selectedStatus = ref('')
|
||||
|
||||
const actionList = ref([
|
||||
{ name: '查看详情', value: 'detail' },
|
||||
{ name: '查看申请', value: 'applications' },
|
||||
{ name: '编辑信息', value: 'edit' },
|
||||
{ name: '修改状态', value: 'status' },
|
||||
{ name: '删除', value: 'delete', color: '#FF5722' }
|
||||
])
|
||||
|
||||
const statusOptions = ref([
|
||||
{
|
||||
value: 'active',
|
||||
label: '招募中',
|
||||
desc: '正在寻找领养家庭',
|
||||
icon: '🟢'
|
||||
},
|
||||
{
|
||||
value: 'paused',
|
||||
label: '已暂停',
|
||||
desc: '暂时停止接收申请',
|
||||
icon: '🟡'
|
||||
},
|
||||
{
|
||||
value: 'completed',
|
||||
label: '已完成',
|
||||
desc: '已找到合适的领养家庭',
|
||||
icon: '🔵'
|
||||
},
|
||||
{
|
||||
value: 'cancelled',
|
||||
label: '已取消',
|
||||
desc: '取消领养计划',
|
||||
icon: '🔴'
|
||||
}
|
||||
])
|
||||
|
||||
// 计算属性
|
||||
const totalCount = computed(() => publishedList.value.length)
|
||||
const activeCount = computed(() => publishedList.value.filter(item => item.status === 'active').length)
|
||||
const completedCount = computed(() => publishedList.value.filter(item => item.status === 'completed').length)
|
||||
|
||||
const filteredList = computed(() => {
|
||||
if (currentFilter.value === 'all') {
|
||||
return publishedList.value
|
||||
}
|
||||
return publishedList.value.filter(item => item.status === currentFilter.value)
|
||||
})
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadPublishedList()
|
||||
})
|
||||
|
||||
// 方法定义
|
||||
const loadPublishedList = () => {
|
||||
try {
|
||||
const savedList = uni.getStorageSync('myPublishedAdoptions') || []
|
||||
|
||||
// 如果没有数据,创建模拟数据
|
||||
if (savedList.length === 0) {
|
||||
const mockData = [
|
||||
{
|
||||
id: 'pub_1',
|
||||
name: '小橘',
|
||||
breed: '橘猫',
|
||||
gender: '公',
|
||||
age: '2岁',
|
||||
photos: ['/static/mock-cat1.jpg'],
|
||||
status: 'active',
|
||||
description: '性格温顺,喜欢和人亲近,已绝育,疫苗齐全。',
|
||||
publishTime: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
applicationCount: 3,
|
||||
viewCount: 25
|
||||
},
|
||||
{
|
||||
id: 'pub_2',
|
||||
name: '小白',
|
||||
breed: '英短',
|
||||
gender: '母',
|
||||
age: '1岁',
|
||||
photos: ['/static/mock-cat2.jpg'],
|
||||
status: 'completed',
|
||||
description: '活泼可爱,适合有经验的铲屎官。',
|
||||
publishTime: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
applicationCount: 8,
|
||||
viewCount: 45
|
||||
}
|
||||
]
|
||||
|
||||
uni.setStorageSync('myPublishedAdoptions', mockData)
|
||||
publishedList.value = mockData
|
||||
} else {
|
||||
publishedList.value = savedList
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载发布列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const savePublishedList = () => {
|
||||
uni.setStorageSync('myPublishedAdoptions', publishedList.value)
|
||||
}
|
||||
|
||||
const setFilter = (filter) => {
|
||||
currentFilter.value = filter
|
||||
}
|
||||
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'active': '招募中',
|
||||
'paused': '已暂停',
|
||||
'completed': '已完成',
|
||||
'cancelled': '已取消'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
const getEmptyText = () => {
|
||||
switch (currentFilter.value) {
|
||||
case 'active':
|
||||
return '暂无招募中的领养信息'
|
||||
case 'completed':
|
||||
return '暂无已完成的领养信息'
|
||||
default:
|
||||
return '还没有发布过领养信息'
|
||||
}
|
||||
}
|
||||
|
||||
const formatTime = (timeString) => {
|
||||
if (!timeString) return ''
|
||||
const date = new Date(timeString)
|
||||
const now = new Date()
|
||||
const diffTime = now - date
|
||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (diffDays === 0) {
|
||||
return '今天'
|
||||
} else if (diffDays === 1) {
|
||||
return '昨天'
|
||||
} else if (diffDays < 7) {
|
||||
return `${diffDays}天前`
|
||||
} else {
|
||||
return date.toLocaleDateString('zh-CN')
|
||||
}
|
||||
}
|
||||
|
||||
const viewDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/adoption/adoption-detail?id=${item.id}&from=published`,
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const showActions = (item) => {
|
||||
currentItem.value = item
|
||||
showActionSheet.value = true
|
||||
}
|
||||
|
||||
const onActionSelect = (action) => {
|
||||
switch (action.value) {
|
||||
case 'detail':
|
||||
viewDetail(currentItem.value)
|
||||
break
|
||||
case 'applications':
|
||||
viewApplications(currentItem.value)
|
||||
break
|
||||
case 'edit':
|
||||
editItem(currentItem.value)
|
||||
break
|
||||
case 'status':
|
||||
changeStatus(currentItem.value)
|
||||
break
|
||||
case 'delete':
|
||||
deleteItem(currentItem.value)
|
||||
break
|
||||
}
|
||||
showActionSheet.value = false
|
||||
}
|
||||
|
||||
const viewApplications = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/adoption/applications?publishId=${item.id}`,
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const editItem = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/adoption/publish?id=${item.id}&mode=edit`,
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const changeStatus = (item) => {
|
||||
currentItem.value = item
|
||||
selectedStatus.value = item.status
|
||||
showStatusModal.value = true
|
||||
}
|
||||
|
||||
const selectStatus = (status) => {
|
||||
selectedStatus.value = status
|
||||
}
|
||||
|
||||
const confirmStatusChange = () => {
|
||||
if (currentItem.value && selectedStatus.value !== currentItem.value.status) {
|
||||
currentItem.value.status = selectedStatus.value
|
||||
savePublishedList()
|
||||
|
||||
uni.showToast({
|
||||
title: '状态已更新',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
showStatusModal.value = false
|
||||
}
|
||||
|
||||
const deleteItem = (item) => {
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: '删除后无法恢复,确定要删除这个领养信息吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
const index = publishedList.value.findIndex(p => p.id === item.id)
|
||||
if (index > -1) {
|
||||
publishedList.value.splice(index, 1)
|
||||
savePublishedList()
|
||||
uni.showToast({
|
||||
title: '已删除',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const publishNew = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/adoption/publish',
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
publishedList,
|
||||
currentFilter,
|
||||
showActionSheet,
|
||||
showStatusModal,
|
||||
selectedStatus,
|
||||
actionList,
|
||||
statusOptions,
|
||||
totalCount,
|
||||
activeCount,
|
||||
completedCount,
|
||||
filteredList,
|
||||
setFilter,
|
||||
getStatusText,
|
||||
getEmptyText,
|
||||
formatTime,
|
||||
viewDetail,
|
||||
showActions,
|
||||
onActionSelect,
|
||||
selectStatus,
|
||||
confirmStatusChange,
|
||||
publishNew
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-published-container {
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
|
||||
min-height: 100vh;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.stats-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
margin: 0 30rpx 24rpx 30rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 20rpx;
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 24rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
|
||||
.stat-number,
|
||||
.stat-label {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #FF8A80;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 发布列表 */
|
||||
.published-list {
|
||||
margin: 0 30rpx;
|
||||
|
||||
.published-item {
|
||||
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);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.item-image {
|
||||
position: relative;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.pet-image {
|
||||
width: 100%;
|
||||
height: 300rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
position: absolute;
|
||||
top: 16rpx;
|
||||
right: 16rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 20rpx;
|
||||
|
||||
&.active {
|
||||
background: rgba(76, 175, 80, 0.9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.paused {
|
||||
background: rgba(255, 152, 0, 0.9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.completed {
|
||||
background: rgba(33, 150, 243, 0.9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.cancelled {
|
||||
background: rgba(244, 67, 54, 0.9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.pet-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
padding: 8rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
|
||||
.action-icon {
|
||||
font-size: 24rpx;
|
||||
color: #FF8A80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pet-info {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
width: 80rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-stats {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.stat-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.stat-icon {
|
||||
font-size: 20rpx;
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
|
||||
.stat-text {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-description {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
line-height: 1.6;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
padding: 16rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 80rpx 40rpx;
|
||||
margin: 0 30rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 24rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
margin-bottom: 32rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.empty-action {
|
||||
display: inline-block;
|
||||
padding: 16rpx 32rpx;
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
border-radius: 20rpx;
|
||||
|
||||
.action-text {
|
||||
font-size: 26rpx;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 浮动发布按钮 */
|
||||
.fab-button {
|
||||
position: fixed;
|
||||
bottom: 120rpx;
|
||||
right: 40rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 138, 128, 0.4);
|
||||
z-index: 100;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.fab-icon {
|
||||
font-size: 48rpx;
|
||||
color: white;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
|
||||
/* 状态选择弹窗 */
|
||||
.status-options {
|
||||
padding: 20rpx 0;
|
||||
|
||||
.status-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
margin-bottom: 16rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(255, 138, 128, 0.05);
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.active {
|
||||
border-color: #FF8A80;
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.option-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
|
||||
&.active {
|
||||
background: rgba(76, 175, 80, 0.1);
|
||||
}
|
||||
|
||||
&.paused {
|
||||
background: rgba(255, 152, 0, 0.1);
|
||||
}
|
||||
|
||||
&.completed {
|
||||
background: rgba(33, 150, 243, 0.1);
|
||||
}
|
||||
|
||||
&.cancelled {
|
||||
background: rgba(244, 67, 54, 0.1);
|
||||
}
|
||||
|
||||
.icon-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.option-info {
|
||||
flex: 1;
|
||||
|
||||
.option-title {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.option-desc {
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 375px) {
|
||||
.my-published-container {
|
||||
.stats-card,
|
||||
.published-list,
|
||||
.empty-state {
|
||||
margin-left: 20rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
gap: 16rpx;
|
||||
|
||||
.stat-item {
|
||||
padding: 20rpx 12rpx;
|
||||
|
||||
.stat-number {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.published-item {
|
||||
padding: 20rpx;
|
||||
|
||||
.item-image {
|
||||
.pet-image {
|
||||
height: 250rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fab-button {
|
||||
right: 30rpx;
|
||||
bottom: 100rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
|
||||
.fab-icon {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20rpx);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.my-published-container > view {
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
.published-item {
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.fab-button {
|
||||
animation: fadeIn 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* 状态过渡动画 */
|
||||
.status-badge {
|
||||
animation: fadeIn 0.4s ease-out;
|
||||
}
|
||||
|
||||
.item-actions:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user