bindbox-mini/components/activity/CabinetPreviewPopup.vue

260 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view v-if="visible" class="cabinet-overlay" @touchmove.stop.prevent>
<view class="cabinet-mask" @tap="close"></view>
<view class="cabinet-panel" @tap.stop>
<view class="cabinet-header">
<text class="cabinet-title">我的盒柜</text>
<text class="cabinet-close" @tap="close">×</text>
</view>
<scroll-view scroll-y class="cabinet-content">
<view v-if="loading" class="cabinet-loading">
<text class="loading-icon">📦</text>
<text class="loading-text">加载中...</text>
</view>
<view v-else-if="items.length === 0" class="cabinet-empty">
<text class="empty-icon">🎁</text>
<text class="empty-text">暂无物品</text>
<text class="empty-hint">参与活动获得奖品后会显示在这里</text>
</view>
<view v-else class="cabinet-grid">
<view v-for="item in displayItems" :key="item.id" class="cabinet-item">
<image class="item-image" :src="item.image" mode="aspectFill" />
<view class="item-info">
<text class="item-name">{{ item.name }}</text>
<text class="item-count">x{{ item.count }}</text>
</view>
</view>
</view>
<view v-if="hasMore" class="load-more" @tap="goFullCabinet">
<text>查看全部 {{ total }} 件物品</text>
<text class="arrow"></text>
</view>
</scroll-view>
</view>
</view>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const props = defineProps({
visible: {
type: Boolean,
default: false
},
activityId: {
type: [String, Number],
default: ''
}
})
const emit = defineEmits(['update:visible'])
const loading = ref(false)
const items = ref([])
const total = ref(0)
const maxDisplay = 6 // 最多显示6个
const displayItems = computed(() => items.value.slice(0, maxDisplay))
const hasMore = computed(() => items.value.length > maxDisplay || total.value > items.value.length)
function close() {
emit('update:visible', false)
}
function goFullCabinet() {
close()
uni.switchTab({ url: '/pages/cabinet/index' })
}
// 模拟加载数据实际项目中应该调用API
async function loadItems() {
if (!props.activityId) return
loading.value = true
try {
// TODO: 调用实际API获取当前活动相关的盒柜物品
// const res = await getUserCabinetItems(props.activityId)
// items.value = res.items || []
// total.value = res.total || 0
// 模拟数据
await new Promise(r => setTimeout(r, 300))
items.value = []
total.value = 0
} catch (e) {
console.error('加载盒柜失败', e)
} finally {
loading.value = false
}
}
watch(() => props.visible, (v) => {
if (v) loadItems()
})
</script>
<style lang="scss" scoped>
.cabinet-overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9000;
}
.cabinet-mask {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(10rpx);
}
.cabinet-panel {
position: absolute;
left: $spacing-lg;
right: $spacing-lg;
bottom: calc(env(safe-area-inset-bottom) + 24rpx);
max-height: 65vh;
background: rgba($bg-card, 0.95);
border-radius: $radius-xl;
box-shadow: $shadow-card;
border: 1rpx solid rgba(255, 255, 255, 0.5);
overflow: hidden;
animation: slideUp 0.25s ease-out;
}
.cabinet-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-lg;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.06);
}
.cabinet-title {
font-size: $font-lg;
font-weight: 800;
color: $text-main;
}
.cabinet-close {
font-size: 48rpx;
line-height: 1;
color: $text-tertiary;
padding: 0 10rpx;
}
.cabinet-content {
max-height: 50vh;
padding: $spacing-lg;
}
.cabinet-loading,
.cabinet-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx $spacing-lg;
}
.loading-icon,
.empty-icon {
font-size: 64rpx;
margin-bottom: $spacing-md;
}
.loading-text,
.empty-text {
font-size: $font-md;
color: $text-sub;
font-weight: 600;
}
.empty-hint {
font-size: $font-xs;
color: $text-tertiary;
margin-top: $spacing-xs;
}
.cabinet-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: $spacing-md;
}
.cabinet-item {
display: flex;
flex-direction: column;
align-items: center;
}
.item-image {
width: 100%;
aspect-ratio: 1 / 1;
border-radius: $radius-md;
background: $bg-secondary;
margin-bottom: $spacing-xs;
}
.item-info {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.item-name {
font-size: $font-xs;
color: $text-main;
font-weight: 600;
@include text-ellipsis(1);
text-align: center;
width: 100%;
}
.item-count {
font-size: 22rpx;
color: $brand-primary;
font-weight: 700;
}
.load-more {
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
padding: $spacing-lg 0;
margin-top: $spacing-md;
color: $brand-primary;
font-size: $font-sm;
font-weight: 600;
border-top: 1rpx solid rgba(0, 0, 0, 0.04);
}
.arrow {
font-size: 28rpx;
font-weight: 700;
}
@keyframes slideUp {
from {
transform: translateY(40rpx);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
</style>