260 lines
5.3 KiB
Vue
260 lines
5.3 KiB
Vue
<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>
|