修正布局,删改无用页面

This commit is contained in:
2026-06-24 08:13:12 +08:00
parent 8d8c823616
commit 0bebce3dc1
24 changed files with 2677 additions and 2796 deletions
+63 -33
View File
@@ -125,18 +125,9 @@
<script setup>
import { ref, computed, onUnmounted } from 'vue'
import { setToken } from '@/utils/request.js'
import { loginWithPhone, oneClickLogin, sendCode } from '@/api/main.js'
// 测试数据
const TEST_TOKEN = 'test_token_123456'
const TEST_MEMBER_INFO = {
memberId: 10001,
memberNo: 'M001',
phone: '13800138000',
nickname: '测试用户',
avatar: '/static/logo.png',
accessToken: TEST_TOKEN,
isNewUser: false
}
// 调用真实后端API,不再使用测试数据
const activeCard = ref('phone')
const phone = ref('')
@@ -230,16 +221,31 @@ async function handlePhoneLogin() {
isLoading.value = true
setTimeout(() => {
setToken(TEST_TOKEN)
uni.setStorageSync('memberInfo', TEST_MEMBER_INFO)
uni.setStorageSync('isLogin', true)
showToast('登录成功')
setTimeout(() => {
uni.switchTab({ url: '/pages/memberInfo/memberInfo' })
}, 1500)
try {
const res = await oneClickLogin({
accessToken: phone.value,
openid: 'uniapp_phone_login',
nickname: '',
avatar: ''
})
if (res && res.accessToken) {
setToken(res.accessToken)
uni.setStorageSync('memberInfo', res)
uni.setStorageSync('isLogin', true)
showToast('登录成功')
setTimeout(() => {
uni.switchTab({ url: '/pages/memberInfo/memberInfo' })
}, 1500)
} else {
showToast('登录失败,请重试')
}
} catch (err) {
console.error('一键登录失败:', err)
showToast(err?.message || '登录失败,请重试')
} finally {
isLoading.value = false
}, 500)
}
}
function triggerAgreementShake() {
@@ -260,12 +266,22 @@ async function handleSendCode() {
isLoading.value = true
setTimeout(() => {
countdown.value = 300
startCountdown()
showToast('验证码已发送')
try {
const res = await sendCode({ phone: smsPhone.value })
if (res && res.success) {
countdown.value = 60
startCountdown()
showToast('验证码已发送')
} else {
showToast(res?.message || '验证码发送失败')
}
} catch (err) {
console.error('发送验证码失败:', err)
showToast(err?.message || '验证码发送失败')
} finally {
isLoading.value = false
}, 300)
}
}
function startCountdown() {
@@ -297,15 +313,29 @@ async function handleSmsLogin() {
isLoading.value = true
setTimeout(() => {
setToken(TEST_TOKEN)
uni.setStorageSync('memberInfo', TEST_MEMBER_INFO)
showToast('登录成功')
setTimeout(() => {
uni.switchTab({ url: '/pages/memberInfo/memberInfo' })
}, 1500)
try {
const res = await loginWithPhone({
phone: smsPhone.value,
code: code.value
})
if (res && res.accessToken) {
setToken(res.accessToken)
uni.setStorageSync('memberInfo', res)
uni.setStorageSync('isLogin', true)
showToast('登录成功')
setTimeout(() => {
uni.switchTab({ url: '/pages/memberInfo/memberInfo' })
}, 1500)
} else {
showToast('登录失败,请重试')
}
} catch (err) {
console.error('验证码登录失败:', err)
showToast(err?.message || '登录失败,请重试')
} finally {
isLoading.value = false
}, 500)
}
}
onUnmounted(() => {
@@ -1,64 +1,57 @@
<template>
<view class="member-info-page">
<!-- 滚动内容区域 -->
<scroll-view scroll-y class="scroll-container theme-light">
<view class="member-scroll-wrap">
<scroll-view scroll-y class="member-scroll">
<view class="member-page">
<MemberInfoHeader
:user-info="userInfo"
:stats="stats"
:isLogin="isLogin"
@user-info="goUserInfo"
@guest-login="handleGuestLogin"
/>
<view class="member-page__body">
<view class="member-page__sections">
<MemberInfoMemberCard
:card-info="cardInfo"
@view-all="goMemberCard"
@renew="onRenewCard"
@purchase="goPurchaseCard"
/>
<MemberInfoQuickActions @action="onQuickAction" />
<MemberInfoBookingList
v-if="isLogin"
:items="bookingPreview"
@view-all="goBooking"
@item-tap="goBooking"
/>
<MemberInfoCheckInList
v-if="isLogin"
:items="checkIns"
@view-all="onCheckInViewAll"
@item-tap="onCheckInTap"
/>
<MemberInfoBodyReport
v-if="isLogin"
:report="bodyReport"
@view-history="onBodyReportHistory"
@view-report="onBodyReportView"
/>
<MemberInfoCouponPoints
v-if="isLogin"
:data="couponPoints"
@view-all="onCouponViewAll"
@use-coupon="onUseCoupon"
@redeem-points="onRedeemPoints"
/>
<MemberInfoReferral
v-if="isLogin"
:data="referral"
@view-rules="onReferralRules"
/>
<MemberInfoSettings v-if="isLogin" @setting="onSetting" />
<MemberInfoLogout v-if="isLogin" @logout="handleLogout" />
</view>
<MemberInfoHeader
:user-info="userInfo"
:stats="stats"
:is-login="isLogin"
@user-info="goUserInfo"
@guest-login="handleGuestLogin"
/>
<view class="member-page__body">
<view class="member-page__sections">
<MemberInfoMemberCard
:card-info="cardInfo"
@view-all="goMemberCard"
@renew="onRenewCard"
@purchase="goPurchaseCard"
/>
<MemberInfoQuickActions @action="onQuickAction" />
<MemberInfoBookingList
v-if="isLogin"
:items="bookingPreview"
@view-all="goBooking"
@item-tap="goBooking"
/>
<MemberInfoCheckInList
v-if="isLogin"
:items="checkIns"
@view-all="onCheckInViewAll"
@item-tap="onCheckInTap"
/>
<MemberInfoCouponPoints
v-if="isLogin"
:data="couponPoints"
@view-all="onCouponViewAll"
@use-coupon="onUseCoupon"
@redeem-points="onRedeemPoints"
/>
<MemberInfoSettings v-if="isLogin" @setting="onSetting" />
<MemberInfoLogout v-if="isLogin" @logout="handleLogout" />
</view>
</view>
</view>
</scroll-view>
</scroll-view>
</view>
<!-- 固定 TabBar -->
<view class="tabbar-fixed">
<TabBar />
<TabBar />
</view>
</view>
</template>
<script setup>
@@ -79,9 +72,7 @@ import MemberInfoMemberCard from '@/components/memberInfo/MemberInfoMemberCard.v
import MemberInfoQuickActions from '@/components/memberInfo/MemberInfoQuickActions.vue'
import MemberInfoBookingList from '@/components/memberInfo/MemberInfoBookingList.vue'
import MemberInfoCheckInList from '@/components/memberInfo/MemberInfoCheckInList.vue'
import MemberInfoBodyReport from '@/components/memberInfo/MemberInfoBodyReport.vue'
import MemberInfoCouponPoints from '@/components/memberInfo/MemberInfoCouponPoints.vue'
import MemberInfoReferral from '@/components/memberInfo/MemberInfoReferral.vue'
import MemberInfoSettings from '@/components/memberInfo/MemberInfoSettings.vue'
import MemberInfoLogout from '@/components/memberInfo/MemberInfoLogout.vue'
import TabBar from '@/components/TabBar.vue'
@@ -91,9 +82,7 @@ const stats = ref({})
const cardInfo = ref({})
const bookingPreview = ref([])
const checkIns = ref([])
const bodyReport = ref({})
const couponPoints = ref({})
const referral = ref({})
const loading = ref(false)
const hasActiveCard = ref(false)
const isLogin = ref(false)
@@ -213,12 +202,21 @@ function refreshFromStore() {
cardInfo.value = pageData.cardInfo
bookingPreview.value = pageData.bookingPreview
checkIns.value = pageData.checkIns
bodyReport.value = pageData.bodyReport
couponPoints.value = pageData.couponPoints
referral.value = pageData.referral
console.log('[memberInfo] refreshFromStore - userInfo.value:', JSON.stringify(userInfo.value))
}
function goUserInfo() {
navigateToPage(PAGE.USER_INFO)
}
function handleGuestLogin() {
console.log('[memberInfo] 用户点击登录区域')
uni.navigateTo({
url: '/pages/memberInfo/login'
})
}
function goMemberCard() {
navigateToPage(PAGE.MEMBER_CARD)
}
@@ -231,17 +229,6 @@ function goBooking() {
navigateToPage(PAGE.BOOKING)
}
function goUserInfo() {
navigateToPage(PAGE.USER_INFO)
}
function handleGuestLogin() {
console.log('[memberInfo] 用户点击登录区域')
uni.navigateTo({
url: '/pages/memberInfo/login'
})
}
function onRenewCard() {
uni.showModal({
title: '续费会员卡',
@@ -258,14 +245,8 @@ function onRenewCard() {
function onQuickAction(type) {
const routes = {
booking: PAGE.COURSE_LIST,
bodyTest: PAGE.BODY_TEST_HOME,
bodyReport: PAGE.BODY_TEST_HISTORY,
trainReport: PAGE.TRAIN_REPORT,
coupon: PAGE.COUPONS,
points: PAGE.POINTS,
referral: PAGE.REFERRAL,
course: PAGE.MY_COURSES
points: PAGE.POINTS
}
if (routes[type]) {
navigateToPage(routes[type])
@@ -284,18 +265,6 @@ function onCheckInTap(item) {
})
}
function onBodyReportHistory() {
navigateToPage(PAGE.BODY_TEST_HISTORY)
}
function onBodyReportView() {
const id = bodyReport.value?.recordId
const url = id
? `${PAGE.BODY_TEST_REPORT}?id=${id}`
: PAGE.BODY_TEST_HISTORY
navigateToPage(url)
}
function onCouponViewAll() {
navigateToPage(PAGE.COUPONS)
}
@@ -308,16 +277,10 @@ function onRedeemPoints() {
navigateToPage(PAGE.POINTS)
}
function onReferralRules() {
navigateToPage(PAGE.REFERRAL)
}
function onSetting(key) {
const labels = {
notify: '通知设置',
password: '修改密码',
privacy: '隐私政策',
nfc: 'NFC 门禁卡',
delete: '注销账户'
}
if (key === 'delete') {
@@ -361,9 +324,7 @@ function handleLogout() {
cardInfo.value = {}
bookingPreview.value = []
checkIns.value = []
bodyReport.value = {}
couponPoints.value = {}
referral.value = {}
hasActiveCard.value = false
refreshFromStore()
uni.showToast({ title: '已退出', icon: 'success' })
@@ -400,12 +361,29 @@ onShow(() => {
@import '@/common/style/memberInfo/member-info-quick-actions.css';
@import '@/common/style/memberInfo/member-info-booking-list.css';
@import '@/common/style/memberInfo/member-info-check-in-list.css';
@import '@/common/style/memberInfo/member-info-body-report.css';
@import '@/common/style/memberInfo/member-info-coupon-points.css';
@import '@/common/style/memberInfo/member-info-referral.css';
@import '@/common/style/memberInfo/member-info-settings.css';
@import '@/common/style/memberInfo/member-info-logout.css';
/* 页面布局:scroll-view + tabbar */
.member-info-page {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
background: var(--gradient-sky);
}
.member-scroll-wrap {
flex: 1;
overflow: hidden;
}
.member-scroll {
height: 100%;
overflow-y: auto;
}
/* 固定 TabBar */
.tabbar-fixed {
position: fixed;
@@ -66,7 +66,7 @@
<view class="pc-payment__methods">
<view class="pc-payment__method pc-payment__method--selected">
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/alipay.png" mode="aspectFit" class="pc-payment__icon" />
<text class="pc-payment__name">支付宝支付</text>
<text class="pc-payment__name">{{ isWebEnv ? '扫码支付 (Web环境)' : 'App支付' }}</text>
<view class="pc-payment__check"></view>
</view>
</view>
@@ -88,6 +88,72 @@
</view>
</view>
</view>
<!-- 二维码支付对话框 (Web环境) -->
<view class="qr-payment-overlay" v-if="showQrPayment" @tap="closeQrPayment">
<view class="qr-payment-dialog" @tap.stop>
<view class="qr-payment-dialog__header">
<text class="qr-payment-dialog__title">{{ qrPaymentStatus === 'pending' ? '扫码支付' : (qrPaymentStatus === 'success' ? '支付成功' : '支付失败') }}</text>
<view class="qr-payment-dialog__close" @tap="closeQrPayment" v-if="qrPaymentStatus !== 'pending'">×</view>
</view>
<view class="qr-payment-dialog__body">
<!-- 待支付状态显示二维码 -->
<template v-if="qrPaymentStatus === 'pending'">
<view class="qr-payment-dialog__order">
<text class="qr-payment-dialog__label">订单信息</text>
<text class="qr-payment-dialog__value">{{ selectedCard?.cardName }} × 1</text>
</view>
<view class="qr-payment-dialog__amount">
<text class="qr-payment-dialog__label">支付金额</text>
<text class="qr-payment-dialog__money">¥{{ selectedCard?.price || 0 }}</text>
</view>
<view class="qr-payment-dialog__qrcode">
<image
v-if="qrCodeUrl"
:src="'https://api.qrserver.com/v1/create-qr-code?size=200x200&data=' + encodeURIComponent(qrCodeUrl)"
class="qr-payment-dialog__qrcode-img"
mode="aspectFit"
/>
<view v-else class="qr-payment-dialog__qrcode-loading">加载中...</view>
</view>
<view class="qr-payment-dialog__tips">
<text class="qr-payment-dialog__tip">请使用支付宝扫码支付</text>
<text class="qr-payment-dialog__tip qr-payment-dialog__tip--warn" v-if="isWebEnv"> 沙箱环境测试</text>
</view>
</template>
<!-- 支付成功状态 -->
<template v-else-if="qrPaymentStatus === 'success'">
<view class="qr-payment-dialog__result">
<text class="qr-payment-dialog__icon"></text>
<text class="qr-payment-dialog__result-text">支付成功</text>
</view>
</template>
<!-- 支付失败状态 -->
<template v-else>
<view class="qr-payment-dialog__result">
<text class="qr-payment-dialog__icon"></text>
<text class="qr-payment-dialog__result-text">支付失败</text>
</view>
</template>
</view>
<view class="qr-payment-dialog__footer">
<template v-if="qrPaymentStatus === 'pending'">
<view class="qr-payment-dialog__btn qr-payment-dialog__btn--secondary" @tap="closeQrPayment">
<text>取消支付</text>
</view>
</template>
<template v-else>
<view class="qr-payment-dialog__btn qr-payment-dialog__btn--primary" @tap="closeQrPayment">
<text>确定</text>
</view>
</template>
</view>
</view>
</view>
</view>
</template>
@@ -95,9 +161,27 @@
import { ref, onMounted, onUnmounted } from 'vue'
import { onBackPress } from '@dcloudio/uni-app'
import MemberInfoSubNav from '@/components/memberInfo/MemberInfoSubNav.vue'
import { purchaseMemberCard, createPayment, getPaymentStatus } from '@/api/main.js'
import { purchaseMemberCard, createPayment, createQrCodePayment, getPaymentStatus } from '@/api/main.js'
import { loadMemberStore } from '@/common/memberInfo/store.js'
// ==================== Web环境检测 ====================
// #ifdef H5
const isWebEnv = typeof navigator !== 'undefined' && !typeof plus !== 'undefined'
// #endif
// #ifndef H5
const isWebEnv = false
// #endif
// ==================== 二维码支付相关状态 ====================
const showQrPayment = ref(false)
const qrPaymentStatus = ref('pending') // pending | success | fail
const qrCodeUrl = ref('')
let qrPaymentResolve = null
let qrPaymentReject = null
let currentQrOrderId = null
let qrPollingTimer = null
let isQrPolling = false
const cardTypes = ref([
{ id: 1, cardName: '月卡', cardType: 'DURATION', validityDays: 30, price: 1, originalPrice: 399 },
{ id: 2, cardName: '季卡', cardType: 'DURATION', validityDays: 90, price: 1, originalPrice: 999 },
@@ -265,6 +349,103 @@ function startPolling(orderId) {
})
}
// ==================== Web环境扫码支付 ====================
function openQrPayment(qrCode, orderId) {
qrCodeUrl.value = qrCode
currentQrOrderId = orderId
qrPaymentStatus.value = 'pending'
showQrPayment.value = true
// 开始轮询支付状态
startQrPolling(orderId)
}
function closeQrPayment() {
showQrPayment.value = false
stopQrPolling()
if (qrPaymentStatus.value === 'pending' && qrPaymentReject) {
qrPaymentReject(new Error('用户取消支付'))
}
qrPaymentResolve = null
qrPaymentReject = null
currentQrOrderId = null
qrCodeUrl.value = ''
}
// ==================== 二维码支付轮询 ====================
function startQrPolling(orderId) {
if (isQrPolling) return
isQrPolling = true
let pollCount = 0
const maxRetry = 300 // 5分钟超时 (300秒)
function doQuery() {
if (!showQrPayment.value || qrPaymentStatus.value !== 'pending') return
pollCount++
getPaymentStatus(orderId)
.then(res => {
if (res.code === 200 && res.data) {
const status = res.data.status || res.data.payStatus
console.log(`[QrPoll] 第 ${pollCount} 次查询,状态:`, status)
if (status === 'SUCCESS') {
qrPaymentStatus.value = 'success'
stopQrPolling()
if (qrPaymentResolve) {
qrPaymentResolve(true)
}
return
} else if (status === 'FAIL' || status === 'CLOSED') {
qrPaymentStatus.value = 'fail'
stopQrPolling()
if (qrPaymentReject) {
qrPaymentReject(new Error('支付失败'))
}
return
}
}
// 继续轮询
if (pollCount < maxRetry && showQrPayment.value && qrPaymentStatus.value === 'pending') {
qrPollingTimer = setTimeout(doQuery, 1000)
} else if (qrPaymentStatus.value === 'pending') {
qrPaymentStatus.value = 'fail'
stopQrPolling()
if (qrPaymentReject) {
qrPaymentReject(new Error('支付超时'))
}
}
})
.catch(err => {
console.error('[QrPoll] 查询异常:', err)
if (pollCount < maxRetry && showQrPayment.value && qrPaymentStatus.value === 'pending') {
qrPollingTimer = setTimeout(doQuery, 1000)
} else if (qrPaymentStatus.value === 'pending') {
qrPaymentStatus.value = 'fail'
stopQrPolling()
if (qrPaymentReject) {
qrPaymentReject(new Error('支付查询失败'))
}
}
})
}
// 延迟 2 秒开始轮询
qrPollingTimer = setTimeout(doQuery, 2000)
}
function stopQrPolling() {
isQrPolling = false
if (qrPollingTimer) {
clearTimeout(qrPollingTimer)
qrPollingTimer = null
}
}
// ==================== 核心购买逻辑 ====================
async function handlePurchase() {
if (!selectedCard.value) {
@@ -278,72 +459,114 @@ async function handlePurchase() {
try {
const store = loadMemberStore()
const memberId = store.memberProfile?.id || store.profile?.id
// if (!memberId) {
// uni.showToast({ title: '请先登录', icon: 'none' })
// loading.value = false
// return
// }
// 金额转换:元 -> 分
const transAmt = String(Math.round(selectedCard.value.price * 100))
const cardName = selectedCard.value.cardName
// 1. 创建支付订单
uni.showLoading({ title: '创建订单中...' })
const payRes = await createPayment({
memberId: memberId,
orderType: 'MEMBER_CARD',
goodsDesc: `购买${cardName}`,
transAmt: transAmt,
tradeType: TRADE_TYPE,
remark: `会员卡类型ID:${selectedCard.value.id}`
})
// 根据环境选择支付方式
if (isWebEnv) {
// ==================== Web环境:扫码支付 ====================
uni.showLoading({ title: '创建订单...' })
if (payRes.code !== 200) {
const payRes = await createQrCodePayment({
memberId: memberId,
orderType: 'MEMBER_CARD',
goodsDesc: `购买${cardName}`,
transAmt: transAmt,
tradeType: 'QRCODE',
remark: `会员卡类型ID:${selectedCard.value.id}`
})
if (payRes.code !== 200) {
uni.hideLoading()
uni.showToast({ title: payRes.message || '创建支付订单失败', icon: 'none' })
loading.value = false
return
}
const payData = payRes.data
const orderId = payData.orderId
const qrCode = payData.qrCode
if (!qrCode) {
uni.hideLoading()
uni.showToast({ title: '获取二维码失败', icon: 'none' })
loading.value = false
return
}
// 显示二维码支付对话框
uni.hideLoading()
uni.showToast({ title: payRes.message || '创建支付订单失败', icon: 'none' })
loading.value = false
return
await new Promise((resolve, reject) => {
qrPaymentResolve = resolve
qrPaymentReject = reject
openQrPayment(qrCode, orderId)
})
// 支付成功后继续购买会员卡
} else {
// ==================== App环境:唤起支付宝App ====================
uni.showLoading({ title: '创建订单...' })
const payRes = await createPayment({
memberId: memberId,
orderType: 'MEMBER_CARD',
goodsDesc: `购买${cardName}`,
transAmt: transAmt,
tradeType: TRADE_TYPE,
remark: `会员卡类型ID:${selectedCard.value.id}`
})
if (payRes.code !== 200) {
uni.hideLoading()
uni.showToast({ title: payRes.message || '创建支付订单失败', icon: 'none' })
loading.value = false
return
}
const payData = payRes.data
const orderId = payData.orderId
const payUrl = payData.payUrl || payData.payInfo || payData.h5PayUrl
if (!payUrl) {
uni.hideLoading()
uni.showToast({ title: '获取支付链接失败', icon: 'none' })
loading.value = false
return
}
// 唤起支付宝
uni.hideLoading()
uni.showLoading({ title: '正在唤起支付宝...' })
try {
await invokeAlipayApp(payUrl)
} catch (err) {
uni.hideLoading()
uni.showToast({ title: err.message || '唤起支付宝失败', icon: 'none' })
loading.value = false
return
}
// 轮询支付状态
uni.showLoading({ title: '等待支付结果...' })
await startPolling(orderId)
}
const payData = payRes.data
const orderId = payData.orderId
// 2. 获取支付链接
const payUrl = payData.payUrl || payData.payInfo || payData.h5PayUrl
if (!payUrl) {
uni.hideLoading()
uni.showToast({ title: '获取支付链接失败', icon: 'none' })
loading.value = false
return
}
// 3. 唤起支付宝 App
uni.hideLoading()
uni.showLoading({ title: '正在唤起支付宝...' })
try {
await invokeAlipayApp(payUrl)
} catch (err) {
uni.hideLoading()
uni.showToast({ title: '唤起支付宝失败,请确认已安装支付宝', icon: 'none' })
loading.value = false
return
}
// 4. 轮询支付状态
uni.showLoading({ title: '等待支付结果...' })
await startPolling(orderId)
// 5. 支付成功,购买会员卡
// 支付成功,购买会员卡
uni.hideLoading()
const memberRes = await purchaseMemberCard({
memberId: memberId,
memberCardId: selectedCard.value.id,
sourceOrderId: orderId
sourceOrderId: currentQrOrderId || currentQrOrderId
})
if (memberRes.code === 200) {
// 关闭二维码对话框
if (showQrPayment.value) {
showQrPayment.value = false
}
uni.showToast({ title: '购买成功 🎉', icon: 'success' })
setTimeout(() => {
uni.redirectTo({
@@ -377,6 +600,7 @@ onUnmounted(() => {
pollingTimer.value = null
}
isPolling.value = false
stopQrPolling()
if (typeof plus !== 'undefined') {
plus.globalEvent.removeEventListener('resume', () => {})
}
@@ -691,4 +915,157 @@ onUnmounted(() => {
font-weight: 600;
color: #FFFFFF;
}
// ==================== 模拟支付对话框 ====================
.mock-payment-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.qr-payment-dialog {
width: 320px;
background: #FFFFFF;
border-radius: 16px;
overflow: hidden;
}
.qr-payment-dialog__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 24px;
border-bottom: 1px solid #E2E8F0;
}
.qr-payment-dialog__title {
font-size: 18px;
font-weight: 600;
color: #1A202C;
}
.qr-payment-dialog__close {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #A0AEC0;
}
.qr-payment-dialog__body {
padding: 24px;
}
.qr-payment-dialog__order,
.qr-payment-dialog__amount {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.qr-payment-dialog__label {
font-size: 14px;
color: #718096;
}
.qr-payment-dialog__value {
font-size: 14px;
color: #2D3748;
}
.qr-payment-dialog__money {
font-size: 24px;
font-weight: 700;
color: #E53E3E;
}
.qr-payment-dialog__qrcode {
display: flex;
justify-content: center;
align-items: center;
padding: 20px 0;
background: #F7FAFC;
border-radius: 8px;
margin: 16px 0;
}
.qr-payment-dialog__qrcode-img {
width: 200px;
height: 200px;
}
.qr-payment-dialog__qrcode-loading {
font-size: 14px;
color: #A0AEC0;
padding: 80px 0;
}
.qr-payment-dialog__tips {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.qr-payment-dialog__tip {
font-size: 12px;
color: #718096;
&--warn {
color: #ED8936;
}
}
.qr-payment-dialog__result {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 0;
}
.qr-payment-dialog__icon {
font-size: 48px;
margin-bottom: 16px;
}
.qr-payment-dialog__result-text {
font-size: 16px;
font-weight: 600;
color: #2D3748;
}
.qr-payment-dialog__footer {
display: flex;
gap: 12px;
padding: 0 24px 24px;
}
.qr-payment-dialog__btn {
flex: 1;
padding: 14px 0;
border-radius: 8px;
text-align: center;
font-size: 16px;
font-weight: 500;
&--primary {
background: #1677FF;
color: #FFFFFF;
}
&--secondary {
background: #E2E8F0;
color: #4A5568;
}
}
</style>