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:
co-authored by
Claude Opus 4.8
parent
f0911c67a0
commit
08e2f6888b
+1
-1
@@ -36,6 +36,6 @@
|
|||||||
"tabIndent": "auto",
|
"tabIndent": "auto",
|
||||||
"tabSize": 2
|
"tabSize": 2
|
||||||
},
|
},
|
||||||
"appid": "wx636bc46a6570e9fd",
|
"appid": "wxae3b39ac443fedc3",
|
||||||
"simulatorPluginLibVersion": {}
|
"simulatorPluginLibVersion": {}
|
||||||
}
|
}
|
||||||
@@ -216,6 +216,7 @@ export interface BannerItem {
|
|||||||
title: string
|
title: string
|
||||||
content: string | null
|
content: string | null
|
||||||
imageUrl: string
|
imageUrl: string
|
||||||
|
videoUrl?: string | null
|
||||||
linkUrl: string
|
linkUrl: string
|
||||||
sortOrder: number
|
sortOrder: number
|
||||||
category: string | null
|
category: string | null
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ function onHoursClick() {
|
|||||||
uni.showToast({ title: '营业时间仅供参考', icon: 'none' })
|
uni.showToast({ title: '营业时间仅供参考', icon: 'none' })
|
||||||
}
|
}
|
||||||
function onPhoneClick() {
|
function onPhoneClick() {
|
||||||
uni.makePhoneCall({ phoneNumber: scenic.value.phone })
|
uni.makePhoneCall({ phoneNumber: scenic.value.phone, fail: () => {} })
|
||||||
}
|
}
|
||||||
function onCopyAddress() {
|
function onCopyAddress() {
|
||||||
uni.setClipboardData({
|
uni.setClipboardData({
|
||||||
|
|||||||
@@ -6,10 +6,11 @@
|
|||||||
<view class="sticky-header">
|
<view class="sticky-header">
|
||||||
<!-- 搜索框 -->
|
<!-- 搜索框 -->
|
||||||
<view class="search-box">
|
<view class="search-box">
|
||||||
<view class="search-icon">
|
<image
|
||||||
<view class="icon-circle" />
|
class="search-icon"
|
||||||
<view class="icon-handle" />
|
src="https://hn12301.oss-cn-shenzhen.aliyuncs.com/hn12301/fangdajing.png"
|
||||||
</view>
|
mode="aspectFit"
|
||||||
|
/>
|
||||||
<input
|
<input
|
||||||
class="search-input"
|
class="search-input"
|
||||||
v-model="searchText"
|
v-model="searchText"
|
||||||
@@ -622,32 +623,11 @@ onShareTimeline(() => ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.search-icon {
|
.search-icon {
|
||||||
position: relative;
|
|
||||||
width: 32rpx;
|
width: 32rpx;
|
||||||
height: 32rpx;
|
height: 32rpx;
|
||||||
margin-right: $spacing-2;
|
margin-right: $spacing-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-circle {
|
|
||||||
width: 20rpx;
|
|
||||||
height: 20rpx;
|
|
||||||
border: 3rpx solid $uv-tips-color;
|
|
||||||
border-radius: 50%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-handle {
|
|
||||||
width: 10rpx;
|
|
||||||
height: 3rpx;
|
|
||||||
background: $uv-tips-color;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 4rpx;
|
|
||||||
right: 0;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ function removePhoto() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function callService() {
|
function callService() {
|
||||||
uni.makePhoneCall({ phoneNumber: '0731-88912301' })
|
uni.makePhoneCall({ phoneNumber: '0731-88912301', fail: () => {} })
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeNoVoucher() {
|
function closeNoVoucher() {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
<!-- 操作 -->
|
<!-- 操作 -->
|
||||||
<view class="record-actions">
|
<view class="record-actions">
|
||||||
<view
|
<view
|
||||||
v-if="r.canCancel"
|
v-if="r.canCancel && r.status !== 'cancelled'"
|
||||||
class="btn-sm btn-sm--outline"
|
class="btn-sm btn-sm--outline"
|
||||||
@tap="showCancelModal(r)"
|
@tap="showCancelModal(r)"
|
||||||
>
|
>
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
<view class="cancel-modal">
|
<view class="cancel-modal">
|
||||||
<text class="cancel-modal__title">取消预约</text>
|
<text class="cancel-modal__title">取消预约</text>
|
||||||
<view class="cancel-modal__body">
|
<view class="cancel-modal__body">
|
||||||
<text class="cancel-modal__text">确定取消该预约吗?未提前取消且未入园将扣除1次年卡使用次数,权益不可恢复。</text>
|
<text class="cancel-modal__text">确定取消 {{ formatReserveDate(cancelRecord?.date) }}{{ cancelRecord?.scenicName }} 的预约吗?</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="cancel-modal__actions">
|
<view class="cancel-modal__actions">
|
||||||
<view class="btn-modal btn-modal--outline" @tap="cancelPopup?.close()">
|
<view class="btn-modal btn-modal--outline" @tap="cancelPopup?.close()">
|
||||||
@@ -325,6 +325,13 @@ watch(activeTab, () => {
|
|||||||
fetchRecords()
|
fetchRecords()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 将预约日期(如 2026-08-05)格式化为「2026 年 8 月 5 日」 */
|
||||||
|
function formatReserveDate(date?: string): string {
|
||||||
|
const m = (date || '').match(/(\d{4})[-/年.](\d{1,2})[-/月.](\d{1,2})/)
|
||||||
|
if (!m) return date || ''
|
||||||
|
return `${m[1]} 年 ${Number(m[2])} 月 ${Number(m[3])} 日`
|
||||||
|
}
|
||||||
|
|
||||||
function showCancelModal(r: ReserveRecord) {
|
function showCancelModal(r: ReserveRecord) {
|
||||||
cancelRecord.value = r
|
cancelRecord.value = r
|
||||||
cancelPopup.value?.open()
|
cancelPopup.value?.open()
|
||||||
|
|||||||
+262
-3
@@ -45,7 +45,7 @@
|
|||||||
<text class="menu-text">常见问题</text>
|
<text class="menu-text">常见问题</text>
|
||||||
<view class="menu-chevron" />
|
<view class="menu-chevron" />
|
||||||
</view>
|
</view>
|
||||||
<view class="menu-item menu-item--last" @click="callService">
|
<view class="menu-item menu-item--last" @click="goService">
|
||||||
<view class="menu-icon-wrap menu-icon-wrap--error">
|
<view class="menu-icon-wrap menu-icon-wrap--error">
|
||||||
<view class="icon-phone" />
|
<view class="icon-phone" />
|
||||||
</view>
|
</view>
|
||||||
@@ -61,11 +61,65 @@
|
|||||||
<text>退出登录</text>
|
<text>退出登录</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 客服热线弹窗 -->
|
||||||
|
<uni-popup ref="servicePopup" type="center" :mask-click="true">
|
||||||
|
<view class="service-modal">
|
||||||
|
<text class="service-modal__title">客服热线</text>
|
||||||
|
<scroll-view scroll-y class="service-modal__scroll">
|
||||||
|
<view v-if="serviceLoading" class="service-modal__state">
|
||||||
|
<text class="service-modal__tips">加载中...</text>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="serviceList.length === 0" class="service-modal__state">
|
||||||
|
<text class="service-modal__tips">暂无客服信息</text>
|
||||||
|
</view>
|
||||||
|
<template v-else>
|
||||||
|
<view v-for="item in serviceList" :key="item.id" class="service-item">
|
||||||
|
<text class="service-item__title">{{ item.title }}</text>
|
||||||
|
<view v-if="item.content" class="service-item__divider" />
|
||||||
|
<template v-for="(part, i) in parseParts(item.content || '')" :key="i">
|
||||||
|
<rich-text
|
||||||
|
v-if="part.html"
|
||||||
|
class="service-item__content"
|
||||||
|
:nodes="fixRichHtml(part.html)"
|
||||||
|
/>
|
||||||
|
<text
|
||||||
|
v-else-if="part.phone"
|
||||||
|
class="service-item__phone"
|
||||||
|
@click="callPhone(part.phone)"
|
||||||
|
>{{ part.phone }}</text>
|
||||||
|
<video
|
||||||
|
v-else-if="part.videoSrc"
|
||||||
|
class="service-item__video"
|
||||||
|
:src="part.videoSrc"
|
||||||
|
controls
|
||||||
|
object-fit="contain"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<image v-if="item.imageUrl" class="service-item__image" :src="item.imageUrl" mode="widthFix" />
|
||||||
|
<video
|
||||||
|
v-if="item.videoUrl"
|
||||||
|
class="service-item__video"
|
||||||
|
:src="item.videoUrl"
|
||||||
|
controls
|
||||||
|
object-fit="contain"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="service-modal__close" @tap="servicePopup?.close()">
|
||||||
|
<text class="service-modal__close-text">关闭</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import { useUserStore } from '../../store/user'
|
import { useUserStore } from '../../store/user'
|
||||||
|
import { post } from '../../api/request'
|
||||||
|
import type { BannerItem } from '../../api/types'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
@@ -103,8 +157,107 @@ function goUsageGuide() { uni.navigateTo({ url: '/packages/content/pages/usage-g
|
|||||||
/** 跳转订单列表 */
|
/** 跳转订单列表 */
|
||||||
function goOrders() { uni.navigateTo({ url: '/packages/user/pages/order/list' }) }
|
function goOrders() { uni.navigateTo({ url: '/packages/user/pages/order/list' }) }
|
||||||
|
|
||||||
/** 拨打客服热线 */
|
interface ContentPart {
|
||||||
function callService() { uni.makePhoneCall({ phoneNumber: '400-123-0101' }) }
|
html?: string
|
||||||
|
videoSrc?: string
|
||||||
|
phone?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 常见电话号码:手机号 / 400 / 座机 */
|
||||||
|
const PHONE_REGEX = /1[3-9]\d{9}|400-?\d{3}-?\d{4}|\d{3,4}-\d{7,8}/g
|
||||||
|
|
||||||
|
/** 仅含空白与标签的 html 片段无需渲染 */
|
||||||
|
function isBlankHtml(html: string): boolean {
|
||||||
|
return /^\s*(<[^>]+>\s*)*$/.test(html)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 富文本图片防溢出(与 notice-detail 一致) */
|
||||||
|
function fixRichHtml(html: string): string {
|
||||||
|
if (!html) return ''
|
||||||
|
const style = 'max-width:100%;height:auto;display:block;'
|
||||||
|
return html
|
||||||
|
.replace(/<video[\s\S]*?<\/video>/gi, '')
|
||||||
|
.replace(/<img(?![^>]*max-width)[^>]*>/gi, (tag: string) => {
|
||||||
|
if (/style="[^"]*"/i.test(tag)) {
|
||||||
|
return tag.replace(/style="([^"]*)"/i, (_: string, s: string) => `style="${s};${style}"`)
|
||||||
|
}
|
||||||
|
return tag.replace(/<img/i, `<img style="${style}"`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将富文本拆分为 html 段、可拨号电话段与原生 video 段,保持原有上下顺序 */
|
||||||
|
function parseParts(html: string): ContentPart[] {
|
||||||
|
const parts: ContentPart[] = []
|
||||||
|
let htmlBuffer = ''
|
||||||
|
const flushHtml = () => {
|
||||||
|
if (htmlBuffer && !isBlankHtml(htmlBuffer)) parts.push({ html: htmlBuffer })
|
||||||
|
htmlBuffer = ''
|
||||||
|
}
|
||||||
|
/** 纯文本中提取电话号码,拆出可点击拨号段 */
|
||||||
|
const pushText = (text: string) => {
|
||||||
|
let last = 0
|
||||||
|
PHONE_REGEX.lastIndex = 0
|
||||||
|
let p: RegExpExecArray | null
|
||||||
|
while ((p = PHONE_REGEX.exec(text)) !== null) {
|
||||||
|
htmlBuffer += text.slice(last, p.index)
|
||||||
|
flushHtml()
|
||||||
|
parts.push({ phone: p[0] })
|
||||||
|
last = p.index + p[0].length
|
||||||
|
}
|
||||||
|
htmlBuffer += text.slice(last)
|
||||||
|
}
|
||||||
|
/** html 片段:标签保留进 html 段,仅在文本节点里提取电话 */
|
||||||
|
const pushHtmlSeg = (seg: string) => {
|
||||||
|
let last = 0
|
||||||
|
const tagRegex = /<[^>]+>/g
|
||||||
|
let t: RegExpExecArray | null
|
||||||
|
while ((t = tagRegex.exec(seg)) !== null) {
|
||||||
|
pushText(seg.slice(last, t.index))
|
||||||
|
htmlBuffer += t[0]
|
||||||
|
last = t.index + t[0].length
|
||||||
|
}
|
||||||
|
pushText(seg.slice(last))
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastIndex = 0
|
||||||
|
const videoRegex = /<video[\s\S]*?<\/video>/gi
|
||||||
|
let m: RegExpExecArray | null
|
||||||
|
while ((m = videoRegex.exec(html)) !== null) {
|
||||||
|
pushHtmlSeg(html.slice(lastIndex, m.index))
|
||||||
|
flushHtml()
|
||||||
|
const srcMatch =
|
||||||
|
m[0].match(/<source[^>]*src=["']([^"']+)["']/i) ||
|
||||||
|
m[0].match(/<video[^>]*src=["']([^"']+)["']/i)
|
||||||
|
parts.push({ videoSrc: srcMatch ? srcMatch[1] : '' })
|
||||||
|
lastIndex = m.index + m[0].length
|
||||||
|
}
|
||||||
|
pushHtmlSeg(html.slice(lastIndex))
|
||||||
|
flushHtml()
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 点击富文本中的电话号码拨号 */
|
||||||
|
function callPhone(phone: string) {
|
||||||
|
uni.makePhoneCall({ phoneNumber: phone, fail: () => {} })
|
||||||
|
}
|
||||||
|
|
||||||
|
const servicePopup = ref<any>(null)
|
||||||
|
const serviceList = ref<BannerItem[]>([])
|
||||||
|
const serviceLoading = ref(false)
|
||||||
|
|
||||||
|
/** 打开客服热线弹窗并拉取客服信息 */
|
||||||
|
async function goService() {
|
||||||
|
servicePopup.value?.open()
|
||||||
|
serviceLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = await post<BannerItem[]>('/mpContent/queryList', { channel: 'pingxiang', type: 'SERVICE_INFO' })
|
||||||
|
serviceList.value = data || []
|
||||||
|
} catch {
|
||||||
|
serviceList.value = []
|
||||||
|
} finally {
|
||||||
|
serviceLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 手机号脱敏显示(138****5678) */
|
/** 手机号脱敏显示(138****5678) */
|
||||||
function formatPhone(phone?: string) {
|
function formatPhone(phone?: string) {
|
||||||
@@ -392,4 +545,110 @@ function formatPhone(phone?: string) {
|
|||||||
font-weight: $font-weight-medium;
|
font-weight: $font-weight-medium;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 客服热线弹窗 */
|
||||||
|
.service-modal {
|
||||||
|
width: 600rpx;
|
||||||
|
background: $color-card;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
padding: 40rpx 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-modal__title {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
font-size: $font-size-xl;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
color: $uv-main-color;
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-modal__scroll {
|
||||||
|
max-height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-modal__state {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 60rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-modal__tips {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $uv-tips-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item {
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item__title {
|
||||||
|
display: block;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
color: $uv-main-color;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item__divider {
|
||||||
|
height: 1rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.06);
|
||||||
|
margin: 24rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item__content {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-main-color;
|
||||||
|
line-height: 1.8;
|
||||||
|
|
||||||
|
::v-deep img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item__phone {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-primary;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item__image {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
margin-top: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item__video {
|
||||||
|
width: 100%;
|
||||||
|
height: 400rpx;
|
||||||
|
background: #000;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
margin-top: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-modal__close {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 80rpx;
|
||||||
|
background: $uv-primary-light;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-modal__close-text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-primary;
|
||||||
|
font-weight: $font-weight-medium;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+30
-55
@@ -82,27 +82,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</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-panel">
|
||||||
<view class="holder-header">
|
|
||||||
<view class="avatar-wrap" @click="previewAvatar">
|
<view class="avatar-wrap" @click="previewAvatar">
|
||||||
<image
|
<image
|
||||||
class="holder-avatar"
|
class="holder-avatar"
|
||||||
@@ -113,39 +94,37 @@
|
|||||||
<view class="zoom-icon" />
|
<view class="zoom-icon" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="holder-main">
|
|
||||||
<text class="holder-name">{{ userInfoData?.userName || '-' }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="holder-details">
|
<view class="holder-details">
|
||||||
<view class="detail-row">
|
<view class="detail-row">
|
||||||
<text class="detail-label">卡种名称</text>
|
<text class="detail-label">姓名:</text>
|
||||||
<text class="detail-value">{{ currentCard.cardModelName }}</text>
|
<text class="detail-value">{{ userInfoData?.userName || '-' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="detail-row">
|
<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">
|
<view class="detail-value-wrap">
|
||||||
<text class="detail-value">{{ currentCard.cardNo }}</text>
|
<text class="detail-value">{{ currentCard.cardNo }}</text>
|
||||||
<text class="copy-btn" @click="copyCardNo">复制</text>
|
<text class="copy-btn" @click="copyCardNo">复制</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="detail-row">
|
<view class="detail-row">
|
||||||
<text class="detail-label">有效期至</text>
|
<text class="detail-label">有效期至:</text>
|
||||||
<text class="detail-value">{{ currentCard.validityTime }}</text>
|
<text class="detail-value">{{ formatDateOnly(currentCard.validityTime) }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="detail-row">
|
<view class="detail-row">
|
||||||
<text class="detail-label">证件类型</text>
|
<text class="detail-label">{{ userInfoData?.idType || '证件' }}:</text>
|
||||||
<text class="detail-value">{{ userInfoData?.idType || '-' }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">证件号码</text>
|
|
||||||
<text class="detail-value">{{ userInfoData?.idNo || '-' }}</text>
|
<text class="detail-value">{{ userInfoData?.idNo || '-' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="detail-row">
|
|
||||||
<text class="detail-label">手机号码</text>
|
|
||||||
<text class="detail-value">{{ userInfoData?.mobile || userStore.userInfo?.phone || '-' }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 入园提示(持卡人信息下方) -->
|
||||||
|
<view class="qrcode-section" v-if="!showFaceModal && !isLeaving">
|
||||||
|
<text class="qrcode-title">入园提示</text>
|
||||||
|
<view>为确保信息安全,现入园核销只能使用人脸核销。</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 底部占位(滑到底时与tabBar的间隔) -->
|
<!-- 底部占位(滑到底时与tabBar的间隔) -->
|
||||||
<view style="height: 48rpx;"/>
|
<view style="height: 48rpx;"/>
|
||||||
@@ -276,6 +255,12 @@ function onCardChange(e: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 有效期只显示年月日(去掉时间部分) */
|
||||||
|
function formatDateOnly(time?: string): string {
|
||||||
|
if (!time) return '-'
|
||||||
|
return time.split(' ')[0]
|
||||||
|
}
|
||||||
|
|
||||||
function previewAvatar() {
|
function previewAvatar() {
|
||||||
if (!userInfoData.value?.img) return
|
if (!userInfoData.value?.img) return
|
||||||
uni.previewImage({
|
uni.previewImage({
|
||||||
@@ -505,18 +490,14 @@ onUnmounted(() => { if (timer) clearInterval(timer) })
|
|||||||
|
|
||||||
/* === 持卡人信息 === */
|
/* === 持卡人信息 === */
|
||||||
.holder-panel {
|
.holder-panel {
|
||||||
|
display: flex; align-items: flex-start; gap: 12px;
|
||||||
margin: 0 20rpx; background: $color-card;
|
margin: 0 20rpx; background: $color-card;
|
||||||
border-radius: 24rpx; padding: 28rpx;
|
border-radius: 24rpx; padding: 28rpx;
|
||||||
box-shadow: 0 4rpx 20rpx rgba(15, 23, 42, 0.06);
|
box-shadow: 0 4rpx 20rpx rgba(15, 23, 42, 0.06);
|
||||||
}
|
}
|
||||||
.holder-header {
|
.avatar-wrap { position: relative; width: 288rpx; height: 358.4rpx; flex-shrink: 0; }
|
||||||
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; }
|
|
||||||
.holder-avatar {
|
.holder-avatar {
|
||||||
width: 96rpx; height: 96rpx; border-radius: 50%;
|
width: 288rpx; height: 358.4rpx; border-radius: 0;
|
||||||
border: 3rpx solid #eeeeee;
|
border: 3rpx solid #eeeeee;
|
||||||
}
|
}
|
||||||
.avatar-zoom {
|
.avatar-zoom {
|
||||||
@@ -536,17 +517,11 @@ onUnmounted(() => { if (timer) clearInterval(timer) })
|
|||||||
bottom: -2rpx; right: -2rpx;
|
bottom: -2rpx; right: -2rpx;
|
||||||
transform: rotate(45deg); border-radius: 1rpx;
|
transform: rotate(45deg); border-radius: 1rpx;
|
||||||
}
|
}
|
||||||
.holder-main { flex: 1; }
|
.holder-details { flex: 1; min-width: 0; align-self: stretch; display: flex; flex-direction: column; justify-content: space-between; gap: 16rpx; }
|
||||||
.holder-name { font-size: $font-size-lg; font-weight: $font-weight-medium; color: $uv-main-color; display: block; }
|
.detail-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 12rpx; }
|
||||||
.holder-tag {
|
.detail-label { font-size: $font-size-sm; color: #909399; flex-shrink: 0; }
|
||||||
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; }
|
|
||||||
.detail-value-wrap { display: flex; align-items: center; gap: 12rpx; }
|
.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 {
|
.copy-btn {
|
||||||
font-size: 22rpx; color: $uv-primary;
|
font-size: 22rpx; color: $uv-primary;
|
||||||
padding: 4rpx 16rpx; border: 1rpx solid $uv-primary;
|
padding: 4rpx 16rpx; border: 1rpx solid $uv-primary;
|
||||||
@@ -557,7 +532,7 @@ onUnmounted(() => { if (timer) clearInterval(timer) })
|
|||||||
/* === 二维码区域 === */
|
/* === 二维码区域 === */
|
||||||
.qrcode-section {
|
.qrcode-section {
|
||||||
display: flex; flex-direction: column; align-items: center;
|
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;
|
border-radius: 24rpx; padding: 28rpx;
|
||||||
box-shadow: 0 4rpx 20rpx rgba(15, 23, 42, 0.06);
|
box-shadow: 0 4rpx 20rpx rgba(15, 23, 42, 0.06);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user