feat: 新增 card-item 和 empty-state 共享组件

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jacobxu666
2026-06-14 17:26:44 +08:00
co-authored by Claude Opus 4.8
parent cdec6ef299
commit c921fd527b
2 changed files with 148 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
<template>
<view class="card-item" @click="$emit('click', card)">
<image class="card-cover" :src="card.coverImage" mode="aspectFill" />
<view class="card-body">
<text class="card-name">{{ card.name }}</text>
<text class="card-desc">{{ card.description }}</text>
<view class="card-footer">
<view class="price-wrap">
<text class="price">¥{{ card.price }}</text>
<text class="original-price" v-if="card.originalPrice">¥{{ card.originalPrice }}</text>
</view>
<text class="scenic-count">{{ card.scenicCount }}个景区</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import type { CardInfo } from '../api/types'
defineProps<{
card: CardInfo
}>()
defineEmits<{
(e: 'click', card: CardInfo): void
}>()
</script>
<style scoped>
.card-item {
display: flex;
background: #fff;
border-radius: 16rpx;
overflow: hidden;
margin-bottom: 20rpx;
}
.card-cover {
width: 200rpx;
height: 160rpx;
flex-shrink: 0;
background: #eee;
}
.card-body {
flex: 1;
padding: 16rpx 20rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-name {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.card-desc {
font-size: 24rpx;
color: #999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.price-wrap {
display: flex;
align-items: baseline;
gap: 8rpx;
}
.price {
font-size: 32rpx;
color: #E74C3C;
font-weight: bold;
}
.original-price {
font-size: 22rpx;
color: #ccc;
text-decoration: line-through;
}
.scenic-count {
font-size: 22rpx;
color: #4A90D9;
background: #E8F0FE;
padding: 4rpx 12rpx;
border-radius: 20rpx;
}
</style>
+49
View File
@@ -0,0 +1,49 @@
<template>
<view class="empty-state">
<text class="empty-icon">{{ icon }}</text>
<text class="empty-text">{{ text }}</text>
<button v-if="buttonText" class="empty-btn" @click="$emit('action')">
{{ buttonText }}
</button>
</view>
</template>
<script setup lang="ts">
defineProps<{
icon?: string
text: string
buttonText?: string
}>()
defineEmits<{
(e: 'action'): void
}>()
</script>
<style scoped>
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 80rpx 40rpx;
}
.empty-icon {
font-size: 80rpx;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
margin-bottom: 30rpx;
}
.empty-btn {
font-size: 28rpx;
color: #4A90D9;
background: #E8F0FE;
border-radius: 30rpx;
padding: 12rpx 40rpx;
}
</style>