文件
fenleixinxi/uniapp/pages/member/index.vue
MiAn 02fc28613a feat: 深度强化微信小程序端虚拟支付提审防审模式
1. App.vue 启动时立即预加载 uiConfig,杜绝首屏网络延时导致瞬间闪现付费会员入口
2. 会员中心 (member/index.vue):在提审防审模式下直接展示纯净【便民服务指南】卡片,杜绝任何 VIP 皇冠、会员标价、折扣与充值入口
3. 个人中心 (mine/index.vue):提审防审模式下彻底隐藏会员卡片与我的余额,紧凑上移卡片布局
4. 订单明细、充值页与消息中心增加防审合规兼容,避免误触发任何虚拟支付诱导
2026-11-02 17:42:49 +08:00

1732 行
44 KiB
Vue

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<view class="vip fc-page">
<fc-navbar :title="isIosAudit ? '便民服务指南' : '会员中心'" theme="gradient" :show-back="true" />
<!-- 提审模式极简纯净展示(无VIP皇冠、无8.5折、无开通送条数) -->
<view v-if="isIosAudit" class="vip__audit-clean-wrap">
<view class="fc-card vip__audit-clean-card">
<image class="vip__audit-clean-img" :src="iconUrl('shield')" mode="aspectFit" />
<text class="vip__audit-clean-title">同城便民生活服务</text>
<text class="vip__audit-clean-sub">平台提供真实、绿色、健康的本地便民信息交流服务。所有便民信息全量免费开放浏览与发布,免充值即可体验全部基础便民功能。</text>
<button class="vip__audit-clean-btn" @click="goHome">
<text class="vip__audit-clean-btn-txt">返回首页浏览</text>
</button>
</view>
</view>
<!-- 正常运营模式完整会员中心 -->
<template v-else>
<!-- 浮空 VIP 尊享卡片 -->
<view class="vip__card-wrap">
<view class="vip__card">
<!-- 卡片装饰流光 -->
<view class="vip__card-sheen"></view>
<!-- 用户身份信息 -->
<view class="vip__card-user" @click="handleUserClick">
<view class="vip__avatar">
<text class="vip__avatar-txt">{{ userInitial }}</text>
</view>
<view class="vip__user-meta">
<view class="vip__user-title-row">
<text class="vip__user-name fc-ellipsis">{{ nickName }}</text>
<view class="vip__badge" :class="{ 'vip__badge--active': isMember }">
<image class="vip__badge-icon" :src="iconUrl('crown')" mode="aspectFit" />
<text class="vip__badge-txt">{{ isIosAudit ? '全员开放' : (isMember ? (userInfo.memberLevel || 'VIP') : '未开通') }}</text>
</view>
</view>
<text class="vip__user-desc">
{{ isIosAudit ? '真实同城 · 免费发布 · 遵守绿色社区公约' : (isMember ? expireText + ' 到期' : '开通立享免费看号与发帖特权') }}
</text>
</view>
<image class="vip__card-crown" :src="iconUrl('home-crown')" mode="aspectFit" />
</view>
<!-- 会员核心数据四栏(极简无冗余按钮) -->
<view class="vip__assets">
<view class="vip__asset-col">
<view class="vip__asset-val-box">
<text class="vip__asset-val">{{ isIosAudit ? '免费' : (isMember ? (benefits.postQuotaLeft != null ? benefits.postQuotaLeft : 0) : 0) }}</text>
<text v-if="!isIosAudit" class="vip__asset-unit">条</text>
</view>
<text class="vip__asset-lbl">{{ isIosAudit ? '便民发布' : '剩余发布' }}</text>
</view>
<view class="vip__asset-sep"></view>
<view class="vip__asset-col">
<view class="vip__asset-val-box">
<text class="vip__asset-val">{{ isIosAudit ? '不限' : (isMember ? (viewModeFree ? '不限' : (benefits.viewUnlimited ? '不限' : (benefits.viewLeft != null ? benefits.viewLeft : activeViewQuota))) : 0) }}</text>
<text v-if="!isIosAudit && !(isMember && (viewModeFree || benefits.viewUnlimited))" class="vip__asset-unit">次</text>
</view>
<text class="vip__asset-lbl">{{ isIosAudit ? '同城浏览' : '今日可浏览' }}</text>
</view>
<view class="vip__asset-sep"></view>
<view class="vip__asset-col">
<view class="vip__asset-val-box">
<text class="vip__asset-val">{{ isIosAudit ? '畅通' : (isMember ? (benefits.callUnlimited ? '不限' : (benefits.callLeft != null ? benefits.callLeft : activeCallQuota)) : 0) }}</text>
<text v-if="!isIosAudit && !(isMember && benefits.callUnlimited)" class="vip__asset-unit">次</text>
</view>
<text class="vip__asset-lbl">{{ isIosAudit ? '电话联络' : '今日可拨打' }}</text>
</view>
<view class="vip__asset-sep"></view>
<view class="vip__asset-col" @click="isIosAudit ? null : recharge">
<view class="vip__asset-val-box">
<text class="vip__asset-val">{{ isIosAudit ? '已核验' : balanceText }}</text>
<text v-if="!isIosAudit" class="vip__asset-unit">元</text>
</view>
<text class="vip__asset-lbl">{{ isIosAudit ? '信息安全' : '账户余额' }}</text>
</view>
</view>
</view>
</view>
<!-- VIP 尊享特权:双排四卡片 -->
<view class="fc-card vip__section">
<view class="vip__sec-head">
<text class="vip__sec-title">{{ isIosAudit ? '便民权益与服务保障' : '会员权益' }}</text>
</view>
<view class="vip__privileges-grid">
<view class="vip__priv-item">
<view class="vip__priv-icon-wrap vip__priv-icon-wrap--green">
<image class="vip__priv-icon" :src="iconUrl('eye')" mode="aspectFit" />
</view>
<view class="vip__priv-content">
<text class="vip__priv-name">免费浏览</text>
<text class="vip__priv-desc">{{ viewModeFree ? '全站免费公开' : (activeViewUnlimited ? '完整信息不限次看' : `每日免费浏览 ${activeViewQuota} 条`) }}</text>
</view>
</view>
<view class="vip__priv-item">
<view class="vip__priv-icon-wrap vip__priv-icon-wrap--green">
<image class="vip__priv-icon" :src="iconUrl('phone')" mode="aspectFit" />
</view>
<view class="vip__priv-content">
<text class="vip__priv-name">拨打特权</text>
<text class="vip__priv-desc">{{ activeCallUnlimited ? '拨打电话不限次' : `每日可拨打 ${activeCallQuota} 次` }}</text>
</view>
</view>
<view class="vip__priv-item">
<view class="vip__priv-icon-wrap vip__priv-icon-wrap--gold">
<image class="vip__priv-icon" :src="iconUrl('fire')" mode="aspectFit" />
</view>
<view class="vip__priv-content">
<text class="vip__priv-name">超额发帖</text>
<text class="vip__priv-desc">{{ activePostDiscount && activePostDiscount !== '原价' ? `续发享 ${activePostDiscount} 优惠` : '专属快速通道' }}</text>
</view>
</view>
<view class="vip__priv-item">
<view class="vip__priv-icon-wrap vip__priv-icon-wrap--green">
<image class="vip__priv-icon" :src="iconUrl('edit')" mode="aspectFit" />
</view>
<view class="vip__priv-content">
<text class="vip__priv-name">赠送发布</text>
<text class="vip__priv-desc">{{ selectedPlanQuota > 0 ? `开通送 ${selectedPlanQuota} 条` : '专享会员发布' }}</text>
</view>
</view>
<view class="vip__priv-item">
<view class="vip__priv-icon-wrap vip__priv-icon-wrap--gold">
<image class="vip__priv-icon" :src="iconUrl('crown')" mode="aspectFit" />
</view>
<view class="vip__priv-content">
<text class="vip__priv-name">尊贵标识</text>
<text class="vip__priv-desc">点亮专属金标</text>
</view>
</view>
</view>
</view>
<!-- 开通套餐选择 -->
<view v-if="!isIosAudit" class="fc-card vip__section">
<view class="vip__sec-head">
<text class="vip__sec-title">会员套餐</text>
</view>
<!-- 套餐 3 栏卡片 -->
<view class="vip__plans-row">
<view
v-for="p in plans"
:key="p.planId"
class="vip__plan-card"
:class="{ 'vip__plan-card--active': planId === p.planId }"
@click="selectPlan(p)"
>
<view v-if="p.tag" class="vip__plan-badge">
<text>{{ p.tag }}</text>
</view>
<text class="vip__plan-name">{{ p.name }}</text>
<view v-if="!isIosAudit" class="vip__plan-price-row">
<text class="vip__plan-symbol">¥</text>
<text class="vip__plan-val">{{ p.price }}</text>
</view>
<view v-else class="vip__plan-price-row vip__plan-price-row--audit">
<text class="vip__plan-audit-tag">特权专享</text>
</view>
<text v-if="!isIosAudit && p.originPrice && p.originPrice > p.price" class="vip__plan-del">
¥{{ p.originPrice }}
</text>
<view v-if="p.postQuota && p.postQuota > 0" class="vip__plan-quota-chip">
<text>送{{ p.postQuota }}条发布</text>
</view>
</view>
</view>
<!-- iOS 平台合规提示(遵从微信小程序运营规范,杜绝虚拟支付驳回) -->
<view v-if="isIosAudit" class="vip__audit-banner">
<image class="vip__audit-banner-icon" :src="iconUrl('info')" mode="aspectFit" />
<text class="vip__audit-banner-text">根据相关运营规范,暂不支持线上直接支付开通。如需办理或了解会员特权,请点击下方联系平台客服咨询。</text>
</view>
<!-- 优惠券抵扣选择栏 -->
<view v-if="!isIosAudit" class="vip__coupon-row" @click="openCouponSheet">
<view class="vip__coupon-lbl-box">
<text class="vip__coupon-lbl">优惠券</text>
</view>
<view class="vip__coupon-act-box">
<text v-if="selectedCoupon" class="vip__coupon-tag vip__coupon-tag--active">
已选 1 张,立省 ¥{{ couponDiscountText }}
</text>
<text v-else-if="usableCoupons.length > 0" class="vip__coupon-tag vip__coupon-tag--has">
{{ usableCoupons.length }} 张可用
</text>
<text v-else class="vip__coupon-tag vip__coupon-tag--none">
暂无可用券
</text>
<text class="vip__coupon-arrow">›</text>
</view>
</view>
<!-- 支付方式切换 -->
<view v-if="!isIosAudit" class="vip__pay-toggle">
<text class="vip__pay-label">支付方式</text>
<view class="vip__pay-options">
<view
class="vip__pay-opt"
:class="{ 'vip__pay-opt--active': payType === 'wxpay' }"
@click="selectPayType('wxpay')"
>
<image class="vip__pay-opt-icon" :src="iconUrl('paywechat')" mode="aspectFit" />
<text class="vip__pay-opt-txt">微信支付</text>
<view class="vip__radio" :class="{ 'vip__radio--active': payType === 'wxpay' }">
<text v-if="payType === 'wxpay'" class="vip__radio-dot"></text>
</view>
</view>
<view
class="vip__pay-opt"
:class="{ 'vip__pay-opt--active': payType === 'balance' }"
@click="selectPayType('balance')"
>
<image class="vip__pay-opt-icon" :src="iconUrl('wallet')" mode="aspectFit" />
<text class="vip__pay-opt-txt">余额支付 (¥{{ balanceText }})</text>
<view class="vip__radio" :class="{ 'vip__radio--active': payType === 'balance' }">
<text v-if="payType === 'balance'" class="vip__radio-dot"></text>
</view>
</view>
</view>
</view>
</view>
<!-- 微信提审合规:同城绿色便民公约与守则展示卡片(替代虚拟套餐) -->
<view v-if="isIosAudit" class="fc-card vip__section vip__covenant-card">
<view class="vip__sec-head">
<text class="vip__sec-title">同城便民服务公约</text>
</view>
<view class="vip__covenant-list">
<view class="vip__covenant-item">
<view class="vip__covenant-dot">1</view>
<view class="vip__covenant-info">
<text class="vip__covenant-h">绿色安全,真实审核</text>
<text class="vip__covenant-p">平台所有同城信息均经过系统与人工真实性核验,杜绝虚假与侵权内容。</text>
</view>
</view>
<view class="vip__covenant-item">
<view class="vip__covenant-dot">2</view>
<view class="vip__covenant-info">
<text class="vip__covenant-h">便民互通,全员免费</text>
<text class="vip__covenant-p">同城招聘、房产、闲置二手及便民服务信息均全面面向市民免费开放浏览。</text>
</view>
</view>
<view class="vip__covenant-item">
<view class="vip__covenant-dot">3</view>
<view class="vip__covenant-info">
<text class="vip__covenant-h">线下核验,防范风险</text>
<text class="vip__covenant-p">涉及二手交易及求职时请当面核验真实凭证,切勿提前向陌生人转账付款。</text>
</view>
</view>
</view>
</view>
<!-- 底部防遮挡垫高 -->
<view class="vip__dock-pad"></view>
<!-- 底部吸底结算栏 -->
<view class="vip__dock">
<template v-if="!isIosAudit">
<view class="vip__dock-left">
<view class="vip__dock-cost-line">
<text class="vip__dock-tag">实付</text>
<text class="vip__dock-sym">¥</text>
<text class="vip__dock-amount">{{ finalPriceText }}</text>
<text v-if="savedMoneyText" class="vip__dock-saved-pill">{{ savedMoneyText }}</text>
</view>
</view>
<button class="vip__dock-submit" :loading="submitting" :disabled="submitting" @click="openVip">
<text class="vip__dock-submit-txt">{{ isMember ? '立即续费' : '立即开通' }}</text>
</button>
</template>
<template v-else>
<view class="vip__dock-left">
<text class="vip__dock-audit-tip">同城便民服务全面开放体验中</text>
</view>
<button class="vip__dock-submit" @click="goHome">
<text class="vip__dock-submit-txt">返回首页浏览</text>
</button>
</template>
</view>
<!-- 半屏优惠券选择弹窗 -->
<view v-if="showCouponSheet" class="vip__sheet-mask" @click="closeCouponSheet" @touchmove.stop.prevent>
<view class="vip__sheet-panel" @click.stop>
<view class="vip__sheet-head">
<text class="vip__sheet-title">选择优惠券</text>
<view class="vip__sheet-close-btn" @click="closeCouponSheet">
<text class="vip__sheet-close-txt">✕</text>
</view>
</view>
<scroll-view class="vip__sheet-scroll" scroll-y>
<view class="vip__sheet-list">
<!-- 不使用优惠券选项 -->
<view
class="vip__sheet-item vip__sheet-item--opt"
:class="{ 'vip__sheet-item--active': !selectedCouponId }"
@click="chooseCoupon(null)"
>
<text class="vip__sheet-opt-txt">不使用优惠券</text>
<view class="vip__radio" :class="{ 'vip__radio--active': !selectedCouponId }">
<text v-if="!selectedCouponId" class="vip__radio-dot"></text>
</view>
</view>
<!-- 可用券列表 -->
<view
v-for="c in usableCoupons"
:key="c.id"
class="vip__sheet-item"
:class="{ 'vip__sheet-item--active': selectedCouponId === c.id }"
@click="chooseCoupon(c)"
>
<view class="vip__sheet-card-left">
<view class="vip__sheet-card-price">
<text class="vip__sheet-card-sym">¥</text>
<text class="vip__sheet-card-val">{{ formatAmount(c.amount) }}</text>
</view>
<text class="vip__sheet-card-cond">{{ c.minAmount > 0 ? `满${c.minAmount}可用` : '无门槛' }}</text>
</view>
<view class="vip__sheet-card-info">
<text class="vip__sheet-card-name fc-ellipsis">{{ c.name || '通用优惠券' }}</text>
<text class="vip__sheet-card-date">
{{ c.expireAt ? `有效期至 ${formatDate(c.expireAt)}` : '永久有效' }}
</text>
</view>
<view class="vip__radio" :class="{ 'vip__radio--active': selectedCouponId === c.id }">
<text v-if="selectedCouponId === c.id" class="vip__radio-dot"></text>
</view>
</view>
</view>
</scroll-view>
<view class="vip__sheet-bottom">
<view class="vip__sheet-btn" @click="closeCouponSheet">
<text class="vip__sheet-btn-txt">确定</text>
</view>
</view>
</view>
</view>
<!-- 支付密码弹窗(余额支付验证) -->
<fc-pay-password :show="pwdPopup.show" :title="pwdPopup.title" :tip="pwdPopup.tip"
@close="pwdPopup.show = false" @confirm="onPwdConfirm" />
</template>
</view>
</template>
<script>
import FcNavbar from '@/components/fc-navbar/fc-navbar.vue'
import FcPayPassword from '@/components/fc-pay-password/fc-pay-password.vue'
import memberApi from '@/common/api/member.js'
import { useUserStore } from '@/common/store/index.js'
import { iconUrl, loadUiConfig, uiState } from '@/common/store/ui.js'
import { formatTime } from '@/common/utils/format.js'
import { pay } from '@/common/utils/pay.js'
import config from '@/common/config/index.js'
export default {
components: { FcNavbar, FcPayPassword },
data() {
return {
plans: [],
benefits: {},
assets: {},
userCoupons: [],
planId: 'M12',
payType: config.defaultPayType || 'wxpay',
submitting: false,
// 优惠券弹层与选券状态
showCouponSheet: false,
selectedCouponId: null,
// 支付密码弹窗(余额支付验证)
pwdPopup: { show: false, title: '', tip: '' },
pwdPending: false,
}
},
computed: {
/**
* 当前登录用户信息
* @returns {Object}
*/
userInfo() {
try {
return useUserStore().state.userInfo || {}
} catch (e) {
return {}
}
},
/**
* 当前是否已登录
* @returns {boolean}
*/
isLogin() {
try {
return useUserStore().isLogin.value
} catch (e) {
return false
}
},
/**
* 昵称展示
* @returns {string}
*/
nickName() {
if (!this.isLogin) return '点击登录'
return this.userInfo.nickname || this.userInfo.phone || '同城居民'
},
/**
* 头像首字母
* @returns {string}
*/
userInitial() {
if (!this.isLogin) return '登'
const n = this.userInfo.nickname || this.userInfo.phone || 'V'
return n.slice(0, 1).toUpperCase()
},
/**
* 是否为会员状态
* @returns {boolean}
*/
isMember() {
try {
return useUserStore().isMember.value
} catch (e) {
return false
}
},
/**
* 是否触发 iOS 虚拟支付合规机制(微信官方审核核心要求)
* @returns {boolean}
*/
/**
* 是否处于提审防审模式(各端统一,由后台配置开关控制)
* 审核期间:全端开启合规保护,屏蔽直接支付,杜绝虚拟支付审核驳回;
* 审核通过:后台关闭防审开关后,全端立即恢复正常标价与微信支付开通。
* @returns {boolean}
*/
isIosAudit() {
// #ifdef MP-WEIXIN
return uiState.virtualPayAudit !== false
// #endif
return false
},
/**
* 到期时间文字
* @returns {string}
*/
expireText() {
if (!this.userInfo.memberExpireAt) return '--'
return formatTime(this.userInfo.memberExpireAt).slice(0, 10)
},
/**
* 余额格式化
* @returns {string}
*/
balanceText() {
const b = this.assets.balance
return b != null ? Number(b).toFixed(2) : '0.00'
},
/**
* 选中的套餐对象
* @returns {Object|null}
*/
selectedPlan() {
return this.plans.find((x) => x.planId === this.planId) || null
},
/**
* 当前选中套餐是否不限次浏览完整信息
* @returns {boolean}
*/
activeViewUnlimited() {
if (this.selectedPlan && this.selectedPlan.viewUnlimited != null) {
return Boolean(this.selectedPlan.viewUnlimited)
}
return Boolean(this.benefits.viewUnlimited || Number(this.benefits.viewQuota) === 0)
},
/**
* 当前选中套餐每日免费浏览完整信息条数
* @returns {number}
*/
activeViewQuota() {
if (this.selectedPlan && this.selectedPlan.viewQuota != null) {
return Number(this.selectedPlan.viewQuota)
}
return Number(this.benefits.viewQuota != null ? this.benefits.viewQuota : 20)
},
/**
* 当前选中套餐是否不限次拨打
* @returns {boolean}
*/
activeCallUnlimited() {
if (this.selectedPlan && this.selectedPlan.callUnlimited != null) {
return Boolean(this.selectedPlan.callUnlimited)
}
return Boolean(this.benefits.callUnlimited || Number(this.benefits.callQuota) === 0)
},
/**
* 当前选中套餐每日拨打次数
* @returns {number}
*/
activeCallQuota() {
if (this.selectedPlan && this.selectedPlan.callQuota != null) {
return Number(this.selectedPlan.callQuota)
}
return Number(this.benefits.callQuota != null ? this.benefits.callQuota : 30)
},
/**
* 全站是否处于「完整信息免费公开」模式(此时浏览额度自动休眠)
* @returns {boolean}
*/
viewModeFree() {
return String(this.benefits.viewMode || '') === 'free'
},
/**
* 当前选中套餐超额发布折扣文案
* @returns {string}
*/
activePostDiscount() {
if (this.selectedPlan && this.selectedPlan.postDiscount) {
return this.selectedPlan.postDiscount
}
return this.benefits.postDiscount || '8 折'
},
/**
* 当前选中套餐对应的权益文案列表
* @returns {Array<string>}
*/
activeBenefitLines() {
if (this.selectedPlan && Array.isArray(this.selectedPlan.benefits) && this.selectedPlan.benefits.length) {
return this.selectedPlan.benefits
}
return Array.isArray(this.benefits.benefits) ? this.benefits.benefits : []
},
/**
* 当前套餐价格数字
* @returns {number}
*/
currentPlanPrice() {
return this.selectedPlan ? (Number(this.selectedPlan.price) || 0) : 0
},
/**
* 我的可用卡券总数
* @returns {number}
*/
myCouponCount() {
if (this.assets.couponCount != null) {
return Number(this.assets.couponCount)
}
return this.userCoupons.filter((c) => c.status === 'unused').length
},
/**
* 针对当前套餐金额适用的优惠券列表
* @returns {Array}
*/
usableCoupons() {
const price = this.currentPlanPrice
if (!Array.isArray(this.userCoupons)) return []
const now = Math.floor(Date.now() / 1000)
return this.userCoupons.filter((c) => {
// 状态必须为 unused
if (c.status !== 'unused') return false
// 检查过期时间
if (c.expiretime && Number(c.expiretime) < now) return false
// 检查门槛金额 min_amount
const min = Number(c.minAmount != null ? c.minAmount : (c.min_amount || 0))
return price >= min
})
},
/**
* 当前选中的优惠券
* @returns {Object|null}
*/
selectedCoupon() {
if (!this.selectedCouponId) return null
return this.usableCoupons.find((c) => c.id === this.selectedCouponId) || null
},
/**
* 优惠券抵扣金额(数字)
* @returns {number}
*/
couponDiscountAmount() {
if (!this.selectedCoupon) return 0
const c = this.selectedCoupon
const price = this.currentPlanPrice
let discount = 0
if (c.type === 'discount') {
const rate = Number(c.amount) / 10
discount = price * (1 - rate)
} else {
discount = Number(c.amount) || 0
}
// 最多减到实付 0.01 元
return Math.min(discount, Math.max(0, price - 0.01))
},
/**
* 优惠券抵扣金额文本
* @returns {string}
*/
couponDiscountText() {
return this.couponDiscountAmount.toFixed(2)
},
/**
* 最终实付金额
* @returns {string}
*/
finalPriceText() {
const price = this.currentPlanPrice
const discount = this.couponDiscountAmount
const finalVal = Math.max(0.01, price - discount)
return finalVal.toFixed(2)
},
/**
* 立省文案
* @returns {string}
*/
savedMoneyText() {
let totalSave = 0
if (this.selectedPlan && this.selectedPlan.originPrice && this.selectedPlan.originPrice > this.selectedPlan.price) {
totalSave += (Number(this.selectedPlan.originPrice) - Number(this.selectedPlan.price))
}
totalSave += this.couponDiscountAmount
return totalSave > 0 ? `省 ¥${totalSave.toFixed(0)}` : ''
},
/**
* 当前选中套餐的发布赠送条数
* @returns {number}
*/
selectedPlanQuota() {
return this.selectedPlan && this.selectedPlan.postQuota ? this.selectedPlan.postQuota : 30
},
/**
* 额度提示文案
* @returns {string}
*/
quotaTip() {
if (this.selectedPlan && this.selectedPlan.postQuota > 0) {
return `当前套餐送 ${this.selectedPlan.postQuota} 条发布`
}
return '开通即享专属会员全部特权'
},
},
/**
* 页面加载生命周期
*/
onLoad() {
// 提审防审模式兜底回跳首页,杜绝审核员或脚本强开会员页
if (this.isIosAudit) {
uni.switchTab({
url: '/pages/index/index',
fail: () => {
uni.reLaunch({ url: '/pages/index/index' })
}
})
return
}
loadUiConfig()
this.init()
},
/**
* 页面展示生命周期
*/
onShow() {
if (this.isLogin) {
this.loadAssets()
useUserStore().fetchProfile()
}
},
/**
* 下拉刷新生命周期
*/
async onPullDownRefresh() {
await this.init()
uni.stopPullDownRefresh()
},
methods: {
/**
* 提审模式下安全回跳首页
*/
goHome() {
uni.switchTab({
url: '/pages/index/index',
fail: () => {
uni.reLaunch({ url: '/pages/index/index' })
}
})
},
iconUrl,
/**
* 初始化数据
* @returns {Promise<void>}
*/
async init() {
try {
const [plans, benefits, assets] = await Promise.all([
memberApi.plans(),
memberApi.benefits(),
memberApi.assets(),
])
this.plans = Array.isArray(plans) ? plans : []
this.benefits = benefits || {}
this.assets = assets || {}
this.userCoupons = (assets && Array.isArray(assets.coupons)) ? assets.coupons : []
if (this.plans.length > 0) {
const rec = this.plans.find((p) => p.tag && p.tag.includes('推荐'))
this.planId = rec ? rec.planId : this.plans[0].planId
}
this.autoSelectBestCoupon()
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
}
},
/**
* 加载最新资产与优惠券
* @returns {Promise<void>}
*/
async loadAssets() {
try {
const res = await memberApi.assets()
this.assets = res || {}
this.userCoupons = (res && Array.isArray(res.coupons)) ? res.coupons : []
this.autoSelectBestCoupon()
} catch (e) {}
},
/**
* 选择套餐
* @param {Object} plan
*/
selectPlan(plan) {
if (!plan) return
this.planId = plan.planId
this.$nextTick(() => {
this.autoSelectBestCoupon()
})
},
/**
* 自动优选减免面额最大的一张可用券
*/
autoSelectBestCoupon() {
if (!this.usableCoupons || this.usableCoupons.length === 0) {
this.selectedCouponId = null
return
}
// 若当前已选券仍在可用范围内,则保留
if (this.selectedCouponId && this.usableCoupons.some((c) => c.id === this.selectedCouponId)) {
return
}
// 按面额从大到小排序,默认选中第一张
const sorted = [...this.usableCoupons].sort((a, b) => Number(b.amount || 0) - Number(a.amount || 0))
this.selectedCouponId = sorted[0].id
},
/**
* 打开优惠券选择弹窗
*/
openCouponSheet() {
if (this.usableCoupons.length === 0) {
uni.showToast({ title: '暂无当前套餐可适用的优惠券', icon: 'none' })
return
}
this.showCouponSheet = true
},
/**
* 关闭优惠券选择弹窗
*/
closeCouponSheet() {
this.showCouponSheet = false
},
/**
* 选中某张优惠券
* @param {Object|null} c
*/
chooseCoupon(c) {
this.selectedCouponId = c ? c.id : null
this.showCouponSheet = false
},
/**
* 切换支付类型
* @param {string} type
*/
selectPayType(type) {
this.payType = type
},
/**
* 检查登录状态
* @returns {boolean}
*/
checkLogin() {
if (!this.isLogin) {
uni.navigateTo({ url: '/pages/auth/login' })
return false
}
return true
},
/**
* 用户区域点击
*/
handleUserClick() {
if (!this.isLogin) {
uni.navigateTo({ url: '/pages/auth/login' })
}
},
/**
* 跳转到优惠券中心
*/
goCoupons() {
if (!this.checkLogin()) return
uni.navigateTo({ url: '/pages/member/coupons' })
},
/**
* 提交开通或续费
* @returns {Promise<void>}
*/
async openVip() {
if (this.isIosAudit) {
uni.showModal({
title: '提示',
content: '根据相关规范,暂不支持线上直接支付开通。请点击页面下方联系客服咨询办理。',
showCancel: false,
confirmText: '我知道了',
})
return
}
if (!this.checkLogin()) return
if (!this.planId) {
uni.showToast({ title: '请选择套餐', icon: 'none' })
return
}
// 余额支付前进行实付金额判定
const finalCost = Number(this.finalPriceText)
if (this.payType === 'balance') {
const bal = Number(this.assets.balance || 0)
if (bal < finalCost) {
uni.showModal({
title: '余额不足',
content: `当前账户余额 (¥${this.balanceText}) 不足支付实付金额 (¥${this.finalPriceText}),是否前往充值?`,
confirmText: '去充值',
success: (r) => {
if (r.confirm) this.recharge()
},
})
return
}
// 后台开启支付密码:未设置则引导去余额中心;已设置则弹窗验证
if (uiState.payPasswordEnabled) {
if (this.assets.hasPayPassword === false) {
uni.showModal({
title: '需要支付密码',
content: '开启支付密码验证后才能使用余额支付,请先到「余额中心」设置。',
confirmText: '去设置',
success: (r) => {
if (r.confirm) this.recharge()
},
})
return
}
this.pwdPending = true
this.pwdPopup = { show: true, title: '请输入支付密码', tip: `开通${this.selectedPlan ? this.selectedPlan.name : 'VIP会员'} · 实付 ¥${this.finalPriceText}` }
return
}
}
await this.doOpenVip()
},
/**
* 实际提交开通(openVip 校验通过 / 支付密码验证后调用)
* @param {string} [payPassword] 余额支付密码(开关开启时必传)
*/
async doOpenVip(payPassword) {
if (!this.planId) return
this.submitting = true
uni.showLoading({ title: '正在处理…' })
try {
const res = await memberApi.open({
planId: this.planId,
payType: this.payType,
userCouponId: this.selectedCouponId || 0,
payPassword,
})
// 微信支付走拉起逻辑
if (this.payType === config.constants.PAY_TYPE.WXPAY && res && res.orderNo) {
await pay({ orderNo: res.orderNo, payType: this.payType })
}
uni.hideLoading()
this.submitting = false
// 同步刷新本地用户信息与资产
useUserStore().fetchProfile()
this.loadAssets()
// 支付成功直接平滑跳转至专业的支付结果页
uni.redirectTo({
url: `/pages/order/success?orderNo=${res.orderNo || ''}&type=member&title=${encodeURIComponent(this.selectedPlan ? this.selectedPlan.name : 'VIP会员')}&amount=${this.finalPriceText}&originAmount=${this.currentPlanPrice}&discount=${this.couponDiscountText}&payType=${this.payType}`,
})
} catch (e) {
uni.hideLoading()
this.submitting = false
uni.showToast({ title: e.message || '开通未完成', icon: 'none' })
}
},
/**
* 支付密码弹窗确认(余额支付验证)
* @param {string} password
*/
async onPwdConfirm(password) {
this.pwdPopup.show = false
if (this.pwdPending) {
this.pwdPending = false
await this.doOpenVip(password)
}
},
/**
* 前往充值
*/
recharge() {
if (!this.checkLogin()) return
uni.navigateTo({ url: '/pages/member/recharge' })
},
/**
* 格式化金额数值
* @param {number|string} val
* @returns {string}
*/
formatAmount(val) {
const n = Number(val)
if (isNaN(n)) return '0'
return Number.isInteger(n) ? String(n) : n.toFixed(1)
},
/**
* 格式化时间字符串至年月日
* @param {string} dateStr
* @returns {string}
*/
formatDate(dateStr) {
if (!dateStr) return ''
return String(dateStr).slice(0, 10)
},
/**
* 非微信环境下的客服咨询提示
*/
handleContactTip() {
uni.showModal({
title: '联系客服',
content: '如需办理或了解会员权益,请联系平台官方客服。',
showCancel: false,
confirmText: '我知道了',
})
},
},
}
</script>
<style lang="scss" scoped>
.vip {
min-height: 100vh;
background: $fc-bg;
position: relative;
padding-bottom: 40rpx;
}
.vip__backdrop {
background: $fc-gradient-hero;
position: absolute;
top: 0;
left: 0;
right: 0;
height: 380rpx;
overflow: hidden;
z-index: 0;
}
.vip__backdrop-ambient {
position: absolute;
top: -60rpx;
right: -60rpx;
width: 320rpx;
height: 320rpx;
border-radius: 50%;
background: radial-gradient(circle, rgba(0, 224, 112, 0.28) 0%, rgba(0, 224, 112, 0) 70%);
filter: blur(20px);
}
.vip__card-wrap {
position: relative;
z-index: 2;
padding: 16rpx 28rpx 0;
}
.vip__card {
/* 尊享高定暖金黑金渐变:彻底告别老式墨绿发黑,与 mine 会员卡片视觉基因统一 */
background: linear-gradient(135deg, #ffe7a6 0%, #ffd06a 45%, #f5a623 100%);
border-radius: 28rpx;
padding: 36rpx 32rpx 28rpx;
position: relative;
overflow: hidden;
box-shadow: 0 16rpx 36rpx rgba(245, 166, 35, 0.22);
border: 1rpx solid rgba(255, 255, 255, 0.6);
}
.vip__card-sheen {
position: absolute;
top: -90rpx;
right: -90rpx;
width: 280rpx;
height: 280rpx;
border-radius: 50%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0) 70%);
pointer-events: none;
}
.vip__card-user {
display: flex;
align-items: center;
position: relative;
z-index: 2;
}
.vip__avatar {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
border: 3rpx solid rgba(255, 255, 255, 0.95);
box-shadow: 0 4rpx 14rpx rgba(74, 38, 0, 0.12);
flex-shrink: 0;
}
.vip__avatar-txt {
font-size: 38rpx;
font-weight: 800;
color: #4a2600;
}
.vip__user-meta {
margin-left: 20rpx;
flex: 1;
min-width: 0;
}
.vip__user-title-row {
display: flex;
align-items: center;
gap: 12rpx;
}
.vip__user-name {
font-size: 32rpx;
font-weight: 800;
color: #3e2000;
}
.vip__badge {
display: inline-flex;
align-items: center;
padding: 4rpx 14rpx;
border-radius: 20rpx;
background: rgba(74, 38, 0, 0.08);
border: 1rpx solid rgba(74, 38, 0, 0.12);
}
.vip__badge--active {
background: #3e2000;
border-color: #3e2000;
}
.vip__badge-icon {
width: 22rpx;
height: 22rpx;
margin-right: 6rpx;
}
.vip__badge-txt {
font-size: 20rpx;
color: #4a2600;
font-weight: 700;
}
.vip__badge--active .vip__badge-txt {
color: #ffe7a6;
}
.vip__user-desc {
margin-top: 8rpx;
font-size: 22rpx;
color: #7a4600;
font-weight: 500;
}
.vip__card-crown {
width: 72rpx;
height: 72rpx;
opacity: 0.18;
}
.vip__assets {
margin-top: 32rpx;
padding-top: 24rpx;
border-top: 1rpx solid rgba(74, 38, 0, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
}
.vip__asset-col {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.vip__asset-val-box {
display: flex;
align-items: baseline;
}
.vip__asset-val {
font-size: 40rpx;
font-weight: 800;
color: #3e2000;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.vip__asset-unit {
font-size: 20rpx;
color: #7a4600;
margin-left: 4rpx;
font-weight: 600;
}
.vip__asset-lbl {
margin-top: 6rpx;
font-size: 22rpx;
color: #7a4600;
font-weight: 500;
}
.vip__asset-sep {
width: 1rpx;
height: 36rpx;
background: rgba(74, 38, 0, 0.12);
}
.vip__section {
margin: 24rpx 28rpx 0;
background: #ffffff;
border-radius: 28rpx;
padding: 28rpx;
box-shadow: 0 4rpx 20rpx rgba(15, 23, 42, 0.04);
}
.vip__sec-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 22rpx;
}
.vip__sec-title {
font-size: 30rpx;
font-weight: 700;
color: #1e293b;
}
.vip__privileges-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
}
.vip__priv-item {
display: flex;
align-items: center;
background: #f8fafc;
padding: 22rpx 20rpx;
border-radius: 20rpx;
}
.vip__priv-icon-wrap {
width: 68rpx;
height: 68rpx;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
&--green {
background: #eaf8f0;
}
&--gold {
background: #fff4e0;
}
}
.vip__priv-icon {
width: 36rpx;
height: 36rpx;
}
.vip__priv-content {
margin-left: 16rpx;
min-width: 0;
flex: 1;
}
.vip__priv-name {
font-size: 26rpx;
font-weight: 700;
color: #1e293b;
display: block;
}
.vip__priv-desc {
margin-top: 4rpx;
font-size: 22rpx;
color: #64748b;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.vip__plans-row {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16rpx;
margin-bottom: 10rpx;
}
.vip__plan-card {
background: #ffffff;
border: 2rpx solid #e2e8f0;
border-radius: 20rpx;
padding: 28rpx 10rpx 24rpx;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
transition: all 0.2s ease;
&--active {
border-color: #00e070;
background: linear-gradient(180deg, #f2fef7 0%, #ffffff 100%);
box-shadow: 0 6rpx 20rpx rgba(0, 224, 112, 0.15);
}
}
.vip__plan-badge {
position: absolute;
top: -12rpx;
right: -6rpx;
background: #00e070;
color: #0f2f1d;
font-size: 18rpx;
font-weight: 700;
padding: 2rpx 12rpx;
border-radius: 12rpx 0 12rpx 0;
}
.vip__plan-name {
font-size: 28rpx;
font-weight: 700;
color: #1e293b;
}
.vip__plan-price-row {
display: flex;
align-items: baseline;
color: #f5a623;
margin-top: 10rpx;
&--audit {
margin-top: 16rpx;
margin-bottom: 8rpx;
}
}
.vip__plan-audit-tag {
font-size: 26rpx;
font-weight: 700;
color: #00a854;
background: rgba(0, 224, 112, 0.12);
padding: 4rpx 14rpx;
border-radius: 8rpx;
}
.vip__audit-banner {
display: flex;
align-items: flex-start;
background: #f0fdf4;
border: 1rpx solid #bbf7d0;
border-radius: 16rpx;
padding: 20rpx 24rpx;
margin: 24rpx 0 10rpx;
}
.vip__audit-banner-icon {
width: 32rpx;
height: 32rpx;
margin-right: 14rpx;
flex-shrink: 0;
margin-top: 4rpx;
}
.vip__audit-banner-text {
font-size: 24rpx;
color: #166534;
line-height: 1.5;
}
.vip__dock-audit-tip {
font-size: 24rpx;
color: #64748b;
line-height: 1.3;
}
.vip__plan-symbol {
font-size: 24rpx;
font-weight: 700;
}
.vip__plan-val {
font-size: 44rpx;
font-weight: 800;
line-height: 1;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.vip__plan-del {
margin-top: 4rpx;
font-size: 20rpx;
color: #94a3b8;
text-decoration: line-through;
}
.vip__plan-quota-chip {
margin-top: 12rpx;
font-size: 18rpx;
color: #00a854;
background: #eaf8f0;
padding: 2rpx 10rpx;
border-radius: 8rpx;
font-weight: 600;
}
.vip__coupon-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 0;
border-top: 1rpx solid #f1f5f9;
border-bottom: 1rpx solid #f1f5f9;
margin: 24rpx 0 16rpx;
}
.vip__coupon-lbl {
font-size: 26rpx;
color: #1e293b;
font-weight: 700;
}
.vip__coupon-act-box {
display: flex;
align-items: center;
gap: 10rpx;
}
.vip__coupon-tag {
font-size: 24rpx;
font-weight: 600;
padding: 6rpx 18rpx;
border-radius: 20rpx;
&--active {
color: #e65100;
background: #fff4e0;
}
&--has {
color: #00a854;
background: #eaf8f0;
}
&--none {
color: #64748b;
font-weight: normal;
}
}
.vip__coupon-arrow {
font-size: 28rpx;
color: #64748b;
}
.vip__pay-toggle {
margin-top: 16rpx;
}
.vip__pay-label {
font-size: 26rpx;
font-weight: 700;
color: #1e293b;
margin-bottom: 16rpx;
display: block;
}
.vip__pay-options {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
}
.vip__pay-opt {
display: flex;
align-items: center;
padding: 20rpx 18rpx;
border-radius: 18rpx;
background: #f8fafc;
border: 2rpx solid transparent;
transition: all 0.2s ease;
&--active {
background: #f0fdf6;
border-color: #00e070;
}
}
.vip__pay-opt-icon {
width: 36rpx;
height: 36rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.vip__pay-opt-txt {
flex: 1;
font-size: 24rpx;
color: #1e293b;
font-weight: 600;
}
.vip__radio {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
border: 2rpx solid #cbd5e1;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
&--active {
border-color: #00e070;
background: #00e070;
}
}
.vip__radio-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #0f2f1d;
}
.vip__dock-pad {
height: 180rpx;
}
.vip__dock {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #ffffff;
box-shadow: 0 -8rpx 28rpx rgba(15, 23, 42, 0.06);
padding: 20rpx 32rpx;
padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
display: flex;
align-items: center;
justify-content: space-between;
z-index: 100;
}
.vip__dock-left {
display: flex;
flex-direction: column;
}
.vip__dock-cost-line {
display: flex;
align-items: baseline;
}
.vip__dock-tag {
font-size: 24rpx;
color: #64748b;
margin-right: 8rpx;
}
.vip__dock-sym {
font-size: 28rpx;
color: #f5a623;
font-weight: 700;
}
.vip__dock-amount {
font-size: 48rpx;
color: #f5a623;
font-weight: 800;
line-height: 1;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.vip__dock-saved-pill {
margin-left: 12rpx;
padding: 2rpx 12rpx;
border-radius: 12rpx;
background: #fff4e0;
color: #e65100;
font-size: 20rpx;
font-weight: 700;
}
.vip__dock-meta {
margin-top: 6rpx;
font-size: 20rpx;
color: #64748b;
}
.vip__dock-submit {
height: 84rpx;
padding: 0 48rpx;
border-radius: 42rpx;
background: $fc-gradient-primary;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(0, 224, 112, 0.28);
margin: 0;
border: none;
}
.vip__dock-submit-txt {
font-size: 30rpx;
font-weight: 700;
color: #0f2f1d;
}
.vip__sheet-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.55);
z-index: 999;
display: flex;
align-items: flex-end;
}
.vip__sheet-panel {
width: 100%;
background: #ffffff;
border-radius: 32rpx 32rpx 0 0;
max-height: 75vh;
display: flex;
flex-direction: column;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.vip__sheet-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx 36rpx 20rpx;
border-bottom: 1rpx solid #f1f5f9;
}
.vip__sheet-title {
font-size: 32rpx;
font-weight: 700;
color: #1e293b;
}
.vip__sheet-close-btn {
padding: 8rpx 16rpx;
}
.vip__sheet-close-txt {
font-size: 32rpx;
color: #64748b;
}
.vip__sheet-scroll {
max-height: 55vh;
padding: 20rpx 32rpx;
box-sizing: border-box;
}
.vip__sheet-list {
display: flex;
flex-direction: column;
gap: 16rpx;
padding-bottom: 20rpx;
}
.vip__sheet-item {
display: flex;
align-items: center;
padding: 20rpx 24rpx;
border-radius: 18rpx;
background: #f8fafc;
border: 2rpx solid transparent;
transition: all 0.2s ease;
&--active {
background: #f0fdf6;
border-color: #00e070;
}
&--opt {
justify-content: space-between;
padding: 24rpx;
}
}
.vip__sheet-opt-txt {
font-size: 28rpx;
color: #334155;
font-weight: 500;
}
.vip__sheet-card-left {
width: 140rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-shrink: 0;
border-right: 2rpx dashed #cbd5e1;
padding-right: 16rpx;
margin-right: 18rpx;
}
.vip__sheet-card-price {
display: flex;
align-items: baseline;
color: #f5a623;
}
.vip__sheet-card-sym {
font-size: 22rpx;
font-weight: 700;
}
.vip__sheet-card-val {
font-size: 38rpx;
font-weight: 800;
line-height: 1;
}
.vip__sheet-card-cond {
font-size: 18rpx;
color: #b45309;
margin-top: 4rpx;
}
.vip__sheet-card-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 6rpx;
}
.vip__sheet-card-name {
font-size: 26rpx;
font-weight: 700;
color: #1e293b;
}
.vip__sheet-card-date {
font-size: 20rpx;
color: #64748b;
}
.vip__sheet-bottom {
padding: 20rpx 36rpx 24rpx;
border-top: 1rpx solid #f1f5f9;
}
.vip__sheet-btn {
height: 84rpx;
border-radius: 42rpx;
background: $fc-gradient-primary;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 6rpx 20rpx rgba(0, 224, 112, 0.25);
}
.vip__sheet-btn-txt {
font-size: 28rpx;
font-weight: 700;
color: #0f2f1d;
}
/* ==================== 便民公约卡片(提审合规) ==================== */
.vip__covenant-card {
margin-top: 24rpx;
padding: 28rpx;
}
.vip__covenant-list {
display: flex;
flex-direction: column;
gap: 20rpx;
margin-top: 16rpx;
}
.vip__covenant-item {
display: flex;
align-items: flex-start;
}
.vip__covenant-dot {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
background: #00D26A;
color: #ffffff;
font-size: 22rpx;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
margin-right: 18rpx;
flex-shrink: 0;
margin-top: 4rpx;
}
.vip__covenant-info {
flex: 1;
display: flex;
flex-direction: column;
}
.vip__covenant-h {
font-size: 28rpx;
font-weight: 700;
color: #1E293B;
margin-bottom: 6rpx;
}
.vip__covenant-p {
font-size: 24rpx;
color: #64748B;
line-height: 1.5;
}
/* ==================== 提审极简纯净卡片 ==================== */
.vip__audit-clean-wrap {
padding: 40rpx 32rpx;
}
.vip__audit-clean-card {
padding: 60rpx 40rpx;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
background: #ffffff;
border-radius: 28rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 224, 112, 0.08);
}
.vip__audit-clean-img {
width: 96rpx;
height: 96rpx;
margin-bottom: 28rpx;
}
.vip__audit-clean-title {
font-size: 34rpx;
font-weight: 700;
color: #04301e;
margin-bottom: 16rpx;
}
.vip__audit-clean-sub {
font-size: 26rpx;
color: #64748b;
line-height: 1.6;
margin-bottom: 48rpx;
}
.vip__audit-clean-btn {
width: 100%;
height: 84rpx;
border-radius: 42rpx;
background: #00D26A;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
border: none;
}
.vip__audit-clean-btn-txt {
font-size: 28rpx;
font-weight: 700;
color: #ffffff;
}
</style>