feat: 客服热线弹窗、取消预约文案与旅游卡页布局优化

- 客服热线改为弹窗拉取 mpContent/queryList 客服信息(SERVICE_INFO),富文本电话可点击拨号
- 取消预约确认弹窗展示具体预约日期与景区名称,取消后隐藏取消按钮
- makePhoneCall 用户取消时静默处理,不再上报异常
- 景区列表搜索图标改为 OSS 图片
- 旅游卡页:人脸头像方形竖版、信息单行靠右、入园提示移至持卡人信息下方等布局优化
- project.config.json appid 同步为 wxae3b39ac443fedc3

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jacobxu666
2026-08-07 18:29:12 +08:00
co-authored by Claude Opus 4.8
parent f0911c67a0
commit 08e2f6888b
8 changed files with 312 additions and 90 deletions
+32 -57
View File
@@ -82,28 +82,9 @@
</view>
</view>
<!-- 入园码二维码 -->
<view class="qrcode-section" v-if="!showFaceModal && !isLeaving">
<text class="qrcode-title">入园提示</text>
<view>为确保信息安全,现入园核销只能使用人脸核销。</view>
<!-- <view class="qrcode-box"> -->
<!-- 为确保信息安全,现入园核销只能使用人脸核销。 -->
<!-- <image
class="qrcode-img"
:src="userInfoData?.qrCode || '/static/qr-demo.png'"
mode="aspectFit"
/> -->
<!-- </view> -->
<!-- <view class="qrcode-countdown">
<view class="countdown-icon" />
<text class="countdown-text">{{ countdown }}秒后自动刷新</text>
</view> -->
</view>
<!-- 持卡人信息(页面底部) -->
<!-- 持卡人信息 -->
<view class="holder-panel">
<view class="holder-header">
<view class="avatar-wrap" @click="previewAvatar">
<view class="avatar-wrap" @click="previewAvatar">
<image
class="holder-avatar"
:src="userInfoData?.img || '/static/logo.png'"
@@ -113,40 +94,38 @@
<view class="zoom-icon" />
</view>
</view>
<view class="holder-main">
<text class="holder-name">{{ userInfoData?.userName || '-' }}</text>
</view>
</view>
<view class="holder-details">
<view class="detail-row">
<text class="detail-label">卡种名称</text>
<text class="detail-value">{{ currentCard.cardModelName }}</text>
<text class="detail-label">姓名:</text>
<text class="detail-value">{{ userInfoData?.userName || '-' }}</text>
</view>
<view class="detail-row">
<text class="detail-label">旅游卡卡号</text>
<text class="detail-label">手机:</text>
<text class="detail-value">{{ userInfoData?.mobile || userStore.userInfo?.phone || '-' }}</text>
</view>
<view class="detail-row">
<text class="detail-label">卡号:</text>
<view class="detail-value-wrap">
<text class="detail-value">{{ currentCard.cardNo }}</text>
<text class="copy-btn" @click="copyCardNo">复制</text>
</view>
</view>
<view class="detail-row">
<text class="detail-label">有效期至</text>
<text class="detail-value">{{ currentCard.validityTime }}</text>
<text class="detail-label">有效期至:</text>
<text class="detail-value">{{ formatDateOnly(currentCard.validityTime) }}</text>
</view>
<view class="detail-row">
<text class="detail-label">证件类型</text>
<text class="detail-value">{{ userInfoData?.idType || '-' }}</text>
</view>
<view class="detail-row">
<text class="detail-label">证件号码</text>
<text class="detail-label">{{ userInfoData?.idType || '证件' }}:</text>
<text class="detail-value">{{ userInfoData?.idNo || '-' }}</text>
</view>
<view class="detail-row">
<text class="detail-label">手机号码</text>
<text class="detail-value">{{ userInfoData?.mobile || userStore.userInfo?.phone || '-' }}</text>
</view>
</view>
</view>
<!-- 入园提示(持卡人信息下方) -->
<view class="qrcode-section" v-if="!showFaceModal && !isLeaving">
<text class="qrcode-title">入园提示</text>
<view>为确保信息安全,现入园核销只能使用人脸核销。</view>
</view>
<!-- 底部占位(滑到底时与tabBar的间隔) -->
<view style="height: 48rpx;"/>
</scroll-view>
@@ -276,6 +255,12 @@ function onCardChange(e: any) {
}
}
/** 有效期只显示年月日(去掉时间部分) */
function formatDateOnly(time?: string): string {
if (!time) return '-'
return time.split(' ')[0]
}
function previewAvatar() {
if (!userInfoData.value?.img) return
uni.previewImage({
@@ -505,18 +490,14 @@ onUnmounted(() => { if (timer) clearInterval(timer) })
/* === 持卡人信息 === */
.holder-panel {
display: flex; align-items: flex-start; gap: 12px;
margin: 0 20rpx; background: $color-card;
border-radius: 24rpx; padding: 28rpx;
box-shadow: 0 4rpx 20rpx rgba(15, 23, 42, 0.06);
}
.holder-header {
display: flex; align-items: center; gap: 20rpx;
padding-bottom: 24rpx; margin-bottom: 20rpx;
border-bottom: 1rpx solid #f7f8fa;
}
.avatar-wrap { position: relative; width: 96rpx; height: 96rpx; flex-shrink: 0; }
.avatar-wrap { position: relative; width: 288rpx; height: 358.4rpx; flex-shrink: 0; }
.holder-avatar {
width: 96rpx; height: 96rpx; border-radius: 50%;
width: 288rpx; height: 358.4rpx; border-radius: 0;
border: 3rpx solid #eeeeee;
}
.avatar-zoom {
@@ -536,17 +517,11 @@ onUnmounted(() => { if (timer) clearInterval(timer) })
bottom: -2rpx; right: -2rpx;
transform: rotate(45deg); border-radius: 1rpx;
}
.holder-main { flex: 1; }
.holder-name { font-size: $font-size-lg; font-weight: $font-weight-medium; color: $uv-main-color; display: block; }
.holder-tag {
display: inline-block; font-size: 22rpx; color: #00b42a;
background: #f0fff4; padding: 2rpx 12rpx; border-radius: 6rpx; margin-top: 6rpx;
}
.holder-details { display: flex; flex-direction: column; gap: 14rpx; }
.detail-row { display: flex; justify-content: space-between; align-items: center; }
.detail-label { font-size: $font-size-sm; color: $uv-tips-color; }
.holder-details { flex: 1; min-width: 0; align-self: stretch; display: flex; flex-direction: column; justify-content: space-between; gap: 16rpx; }
.detail-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 12rpx; }
.detail-label { font-size: $font-size-sm; color: #909399; flex-shrink: 0; }
.detail-value-wrap { display: flex; align-items: center; gap: 12rpx; }
.detail-value { font-size: $font-size-sm; color: $uv-content-color; }
.detail-value { font-size: $font-size-sm; color: $uv-content-color; word-break: break-all; text-align: right; }
.copy-btn {
font-size: 22rpx; color: $uv-primary;
padding: 4rpx 16rpx; border: 1rpx solid $uv-primary;
@@ -557,7 +532,7 @@ onUnmounted(() => { if (timer) clearInterval(timer) })
/* === 二维码区域 === */
.qrcode-section {
display: flex; flex-direction: column; align-items: center;
margin: 0 20rpx 20rpx; background: $color-card;
margin: 20rpx 20rpx 20rpx; background: $color-card;
border-radius: 24rpx; padding: 28rpx;
box-shadow: 0 4rpx 20rpx rgba(15, 23, 42, 0.06);
}