feat: 旅游卡页面功能入口改为SVG图标 + 图标资源优化

- 旅游卡页面(qrcode/index)功能入口:我要入园/我要预约/使用记录/景区权益
- 卡片详情页(detail)新增4宫格功能入口
- SVG图标(4.3MB)转为PNG(99KB)解决主包4MB限制
- tabBar图标从1024x1024缩至81x81修复模拟器启动失败
- 统一各页面区域间距为24rpx

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jacobxu666
2026-06-25 14:07:45 +08:00
co-authored by Claude
parent 94477fb271
commit 4be01b1c75
20 changed files with 73 additions and 134 deletions
+55 -2
View File
@@ -11,6 +11,18 @@
</view> </view>
<text class="card-desc">{{ card.description }}</text> <text class="card-desc">{{ card.description }}</text>
</view> </view>
<!-- 功能入口 -->
<view class="quick-grid">
<view
v-for="item in quickActions"
:key="item.label"
class="quick-item"
@click="onQuickAction(item)"
>
<image class="quick-icon-img" :src="item.icon" mode="aspectFit" />
<text class="quick-label">{{ item.label }}</text>
</view>
</view>
<!-- 权益说明 --> <!-- 权益说明 -->
<view class="section" v-if="card.benefits?.length"> <view class="section" v-if="card.benefits?.length">
<text class="section-title">权益说明</text> <text class="section-title">权益说明</text>
@@ -59,6 +71,17 @@ import type { CardDetail } from '../../../../api/types'
const card = ref<CardDetail | null>(null) const card = ref<CardDetail | null>(null)
const quickActions = [
{ label: '我要入园', icon: '/static/icon/check.png' },
{ label: '我要预约', icon: '/static/icon/reserve.png' },
{ label: '使用记录', icon: '/static/icon/record.png' },
{ label: '景区权益', icon: '/static/icon/scenic.png' },
]
function onQuickAction(item: { label: string }) {
uni.showToast({ title: `${item.label}功能开发中`, icon: 'none' })
}
/** 页面加载时获取年卡详情 */ /** 页面加载时获取年卡详情 */
onLoad((options) => { onLoad((options) => {
if (options?.id) { if (options?.id) {
@@ -84,8 +107,8 @@ function handleBuy() {
} }
</script> </script>
<style scoped> <style lang="scss" scoped>
.page { min-height: 100vh; background: #f5f5f5; padding-bottom: 120rpx; } .page { min-height: 100vh; background: $uv-bg-color; padding-bottom: 120rpx; }
.cover { width: 100%; height: 400rpx; background: #ddd; } .cover { width: 100%; height: 400rpx; background: #ddd; }
.info-card { background: #fff; padding: 24rpx 30rpx; margin-bottom: 16rpx; } .info-card { background: #fff; padding: 24rpx 30rpx; margin-bottom: 16rpx; }
.card-name { font-size: 36rpx; font-weight: bold; color: #333; display: block; } .card-name { font-size: 36rpx; font-weight: bold; color: #333; display: block; }
@@ -110,4 +133,34 @@ function handleBuy() {
.bottom-price .value { font-size: 36rpx; color: #E74C3C; font-weight: bold; } .bottom-price .value { font-size: 36rpx; color: #E74C3C; font-weight: bold; }
.btn-buy { background: #E74C3C; color: #fff; font-size: 30rpx; padding: 20rpx 60rpx; border-radius: 44rpx; border: none; } .btn-buy { background: #E74C3C; color: #fff; font-size: 30rpx; padding: 20rpx 60rpx; border-radius: 44rpx; border: none; }
.loading-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; color: #999; } .loading-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; color: #999; }
/* Quick actions — 功能入口 */
.quick-grid {
display: flex;
justify-content: space-between;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-3 0;
background: $color-card;
border-radius: 16rpx;
box-shadow: $shadow-sm;
}
.quick-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 12rpx;
transition: transform $transition-fast;
&:active { transform: scale(0.92); }
}
.quick-icon-img { width: 88rpx; height: 88rpx; }
.quick-label {
font-size: 24rpx;
color: $uv-main-color;
font-weight: $font-weight-medium;
}
</style> </style>
+4 -4
View File
@@ -140,10 +140,10 @@ import type { ScenicSpotItem } from '../../data/scenic-spots'
/** 金刚区 */ /** 金刚区 */
const quickActions = [ const quickActions = [
{ label: '我要绑卡', icon: '/static/icon/card.svg' }, { label: '我要绑卡', icon: '/static/icon/card.png' },
{ label: '我要预约', icon: '/static/icon/reserve.svg' }, { label: '我要预约', icon: '/static/icon/reserve.png' },
{ label: '我要入园', icon: '/static/icon/check.svg' }, { label: '我要入园', icon: '/static/icon/check.png' },
{ label: '常见问题', icon: '/static/icon/faq.svg' }, { label: '常见问题', icon: '/static/icon/faq.png' },
] ]
function onQuickAction(item: { label: string }) { function onQuickAction(item: { label: string }) {
+14 -83
View File
@@ -51,29 +51,9 @@
<!-- 功能入口 --> <!-- 功能入口 -->
<view class="feature-panel"> <view class="feature-panel">
<view class="feature-grid"> <view class="feature-grid">
<view class="feature-item" @click="goBindCard"> <view class="feature-item" v-for="item in featureActions" :key="item.label" @click="onFeatureClick(item)">
<view class="feature-icon-wrap"> <image class="feature-icon-img" :src="item.icon" mode="aspectFit" />
<view class="fi-link" /> <text class="feature-label">{{ item.label }}</text>
</view>
<text class="feature-label">绑定旅游卡</text>
</view>
<view class="feature-item" @click="onFeature('reserve')">
<view class="feature-icon-wrap">
<view class="fi-calendar" />
</view>
<text class="feature-label">景区预约</text>
</view>
<view class="feature-item" @click="onFeature('history')">
<view class="feature-icon-wrap">
<view class="fi-list" />
</view>
<text class="feature-label">使用记录</text>
</view>
<view class="feature-item" @click="onFeature('spots')">
<view class="feature-icon-wrap">
<view class="fi-mountain" />
</view>
<text class="feature-label">权益景区</text>
</view> </view>
</view> </view>
</view> </view>
@@ -234,8 +214,15 @@ function goBindCard() {
uni.navigateTo({ url: '/packages/user/pages/card/bind' }) uni.navigateTo({ url: '/packages/user/pages/card/bind' })
} }
function onFeature(type: string) { const featureActions = [
uni.showToast({ title: '功能开发中', icon: 'none' }) { label: '我要入园', icon: '/static/icon/check.png' },
{ label: '我要预约', icon: '/static/icon/reserve.png' },
{ label: '使用记录', icon: '/static/icon/record.png' },
{ label: '景区权益', icon: '/static/icon/scenic.png' },
]
function onFeatureClick(item: { label: string }) {
uni.showToast({ title: `${item.label}功能开发中`, icon: 'none' })
} }
onMounted(() => { startTimer() }) onMounted(() => { startTimer() })
@@ -388,65 +375,9 @@ onUnmounted(() => { if (timer) clearInterval(timer) })
min-width: 110rpx; transition: opacity 150ms; min-width: 110rpx; transition: opacity 150ms;
} }
.feature-item:active { opacity: 0.6; } .feature-item:active { opacity: 0.6; }
.feature-icon-wrap { .feature-icon-img {
width: 88rpx; height: 88rpx; border-radius: 20rpx; width: 88rpx; height: 88rpx;
background: #F1F5F9;
display: flex; align-items: center; justify-content: center;
margin-bottom: 10rpx; margin-bottom: 10rpx;
transition: background 150ms;
} }
.feature-item:active .feature-icon-wrap { background: #E2E8F0; }
.feature-label { font-size: 24rpx; color: #475569; } .feature-label { font-size: 24rpx; color: #475569; }
/* CSS 图标 — 统一使用页面主色 #0052FF */
.fi-link {
width: 24rpx; height: 24rpx;
border: 3rpx solid #0052FF; border-radius: 50%;
position: relative;
}
.fi-link::before {
content: ''; position: absolute;
top: 50%; left: 50%;
width: 10rpx; height: 10rpx;
background: #0052FF; border-radius: 50%;
transform: translate(-50%, -50%);
}
.fi-calendar {
width: 28rpx; height: 28rpx;
border: 3rpx solid #0052FF; border-radius: 4rpx;
position: relative;
}
.fi-calendar::before {
content: ''; position: absolute;
top: 10rpx; left: 4rpx; right: 4rpx;
height: 3rpx; background: #0052FF;
}
.fi-calendar::after {
content: ''; position: absolute;
top: -6rpx; left: 6rpx;
width: 3rpx; height: 10rpx; background: #0052FF;
border-radius: 1rpx;
box-shadow: 10rpx 0 0 #0052FF;
}
.fi-list { width: 28rpx; display: flex; flex-direction: column; gap: 6rpx; }
.fi-list::before, .fi-list::after {
content: ''; height: 3rpx; background: #0052FF; border-radius: 1rpx;
}
.fi-list::before { width: 100%; }
.fi-list::after { width: 70%; }
.fi-mountain {
width: 0; height: 0;
border-left: 16rpx solid transparent;
border-right: 16rpx solid transparent;
border-bottom: 24rpx solid #0052FF;
position: relative;
}
.fi-mountain::after {
content: ''; position: absolute;
top: 12rpx; left: -6rpx;
width: 0; height: 0;
border-left: 10rpx solid transparent;
border-right: 10rpx solid transparent;
border-bottom: 16rpx solid #4D7CFF;
}
</style> </style>
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 658 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 612 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 677 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 814 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 608 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 7.4 KiB