745 lines
18 KiB
Vue
745 lines
18 KiB
Vue
<template>
|
|
<view v-if="visible" class="guide-modal-wrapper" @touchmove.stop.prevent="handlePreventMove">
|
|
<!-- 背景遮罩 -->
|
|
<view class="modal-mask" @click="handleClose"></view>
|
|
|
|
<!-- 弹窗容器 -->
|
|
<view class="modal-container" @click.stop>
|
|
<!-- 背景图片 -->
|
|
<image class="modal-background" src="/static/nft/beijingban.png" mode="aspectFill"></image>
|
|
|
|
<!-- 蒙层 -->
|
|
<view class="modal-overlay"></view>
|
|
|
|
<!-- 内容区域 -->
|
|
<view class="modal-content">
|
|
<!-- 顶部区域:返回按钮和标题 -->
|
|
<view class="modal-header">
|
|
<!-- 返回按钮 -->
|
|
<view class="back-button" @click="handleClose">
|
|
<image class="back-icon" src="/static/icon/back.png" mode="aspectFit" />
|
|
</view>
|
|
|
|
<!-- 标题 -->
|
|
<view class="modal-title">新手引导</view>
|
|
</view>
|
|
|
|
<!-- 引导列表 -->
|
|
<scroll-view class="modal-body" scroll-y :show-scrollbar="false">
|
|
<view
|
|
v-for="item in guideList"
|
|
:key="item.key"
|
|
class="guide-item"
|
|
:class="{ 'in-progress': item.status === 'in_progress' }"
|
|
>
|
|
<view class="guide-item-header">
|
|
<view class="guide-status-badge" :class="item.status">
|
|
{{ item.statusText }}
|
|
</view>
|
|
<text class="guide-name">{{ item.name }}</text>
|
|
</view>
|
|
|
|
<view class="guide-item-body">
|
|
<text class="guide-desc">{{ item.desc }}</text>
|
|
</view>
|
|
|
|
<!-- 进度条(进行中状态显示) -->
|
|
<view v-if="item.status === 'in_progress'" class="guide-progress">
|
|
<view class="progress-bar">
|
|
<view
|
|
class="progress-fill"
|
|
:style="{ width: item.progress.percentage + '%' }"
|
|
></view>
|
|
</view>
|
|
<text class="progress-text">{{ item.progress.completed }}/{{ item.progress.total }} 步骤</text>
|
|
</view>
|
|
|
|
<view class="guide-item-footer">
|
|
<!-- 未开始 -->
|
|
<view
|
|
v-if="item.buttonType === 'start'"
|
|
class="guide-btn start-btn"
|
|
@click="handleStartGuide(item.key)"
|
|
>
|
|
{{ item.buttonText }}
|
|
</view>
|
|
<!-- 进行中 -->
|
|
<view
|
|
v-else-if="item.buttonType === 'continue'"
|
|
class="guide-btn continue-btn"
|
|
@click="handleContinueGuide(item.key)"
|
|
>
|
|
{{ item.buttonText }}
|
|
</view>
|
|
<!-- 已完成(可领取) -->
|
|
<view
|
|
v-else-if="item.buttonType === 'claim'"
|
|
class="guide-btn claim-btn"
|
|
@click="handleClaimReward(item.key)"
|
|
>
|
|
{{ item.buttonText }}
|
|
</view>
|
|
<!-- 已领取 -->
|
|
<view
|
|
v-else
|
|
class="guide-btn disabled-btn"
|
|
>
|
|
{{ item.buttonText }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<!-- 底部统计 -->
|
|
<view class="modal-footer">
|
|
<view class="footer-stats">
|
|
已完成 {{ doneCount }}/{{ totalCount }}
|
|
</view>
|
|
<view v-if="claimableCount > 0" class="footer-claim-tip">
|
|
有 {{ claimableCount }} 个奖励可领取
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, watch } from 'vue'
|
|
import { getOnboardingStatus, claimOnboardingReward, completeGuide } from '@/utils/task-api.js'
|
|
import {
|
|
getGuideConfig,
|
|
getGuideStatusList,
|
|
getStepProgress,
|
|
hasGuideProgress,
|
|
getNextIncompleteStep,
|
|
getStepPage,
|
|
clearSubStepProgress,
|
|
resetGuide,
|
|
claimGuideReward,
|
|
markGuideDone,
|
|
onboardingStages
|
|
} from '@/utils/guideConfig.js'
|
|
|
|
const props = defineProps({
|
|
visible: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits(['close', 'updated'])
|
|
|
|
const loading = ref(true)
|
|
const guideList = ref([])
|
|
|
|
// 统计数据
|
|
const totalCount = computed(() => guideList.value.length)
|
|
const doneCount = computed(() => guideList.value.filter(item =>
|
|
item.status === 'completed' || item.status === 'reward_claimed'
|
|
).length)
|
|
const claimableCount = computed(() => guideList.value.filter(item => item.status === 'completed').length)
|
|
|
|
// 保存滚动位置和页面状态
|
|
let scrollTop = 0
|
|
let bodyOverflow = ''
|
|
let pageScrollEnabled = true
|
|
|
|
// 锁定背景页面滚动
|
|
function lockBodyScroll() {
|
|
// 获取当前页面滚动位置
|
|
uni.createSelectorQuery().selectViewport().scrollOffset(res => {
|
|
if (res) {
|
|
scrollTop = res.scrollTop || 0
|
|
}
|
|
}).exec()
|
|
|
|
// #ifdef H5
|
|
// H5 平台:锁定 body 滚动
|
|
const body = document.body
|
|
bodyOverflow = body.style.overflow
|
|
body.style.overflow = 'hidden'
|
|
body.style.position = 'fixed'
|
|
body.style.top = `-${scrollTop}px`
|
|
body.style.width = '100%'
|
|
// #endif
|
|
|
|
// #ifdef MP
|
|
// 小程序平台:禁用页面滚动
|
|
uni.pageScrollTo({
|
|
scrollTop: scrollTop,
|
|
duration: 0
|
|
})
|
|
// #endif
|
|
|
|
// #ifdef APP-PLUS
|
|
// APP 平台:禁用页面滚动
|
|
const currentWebview = plus.webview.currentWebview()
|
|
if (currentWebview) {
|
|
pageScrollEnabled = currentWebview.isScrollEnabled()
|
|
currentWebview.setStyle({
|
|
scrollIndicator: 'none',
|
|
bounce: 'none'
|
|
})
|
|
// 尝试禁用滚动
|
|
try {
|
|
currentWebview.setStyle({ scrollEnabled: false })
|
|
} catch (e) {
|
|
console.log('APP 平台禁用滚动失败:', e)
|
|
}
|
|
}
|
|
// #endif
|
|
}
|
|
|
|
// 解锁背景页面滚动
|
|
function unlockBodyScroll() {
|
|
// #ifdef H5
|
|
// H5 平台:恢复 body 滚动
|
|
const body = document.body
|
|
body.style.overflow = bodyOverflow
|
|
body.style.position = ''
|
|
body.style.top = ''
|
|
body.style.width = ''
|
|
// 恢复滚动位置
|
|
window.scrollTo(0, scrollTop)
|
|
// #endif
|
|
|
|
// #ifdef MP
|
|
// 小程序平台:恢复页面滚动
|
|
uni.pageScrollTo({
|
|
scrollTop: scrollTop,
|
|
duration: 0
|
|
})
|
|
// #endif
|
|
|
|
// #ifdef APP-PLUS
|
|
// APP 平台:恢复页面滚动
|
|
const currentWebview = plus.webview.currentWebview()
|
|
if (currentWebview) {
|
|
currentWebview.setStyle({
|
|
scrollIndicator: 'auto',
|
|
bounce: 'vertical'
|
|
})
|
|
// 恢复滚动
|
|
try {
|
|
currentWebview.setStyle({ scrollEnabled: pageScrollEnabled })
|
|
} catch (e) {
|
|
console.log('APP 平台恢复滚动失败:', e)
|
|
}
|
|
}
|
|
// #endif
|
|
}
|
|
|
|
// 监听 visible 变化
|
|
watch(() => props.visible, (newVal) => {
|
|
if (newVal) {
|
|
initBackend()
|
|
// 锁定背景页面滚动
|
|
lockBodyScroll()
|
|
} else {
|
|
// 解锁背景页面滚动
|
|
unlockBodyScroll()
|
|
}
|
|
}, { immediate: true })
|
|
|
|
// 刷新引导列表
|
|
function refreshList() {
|
|
const rawList = getGuideStatusList()
|
|
guideList.value = rawList.map(item => {
|
|
const progress = getStepProgress(item.key)
|
|
const status = calculateStatus(item.key, item.done, item.claimed)
|
|
|
|
return {
|
|
...item,
|
|
progress,
|
|
status,
|
|
statusText: getStatusText(status, progress),
|
|
buttonText: getButtonText(status),
|
|
buttonType: getButtonType(status)
|
|
}
|
|
})
|
|
}
|
|
|
|
function calculateStatus(key, done, claimed) {
|
|
if (claimed) return 'reward_claimed'
|
|
if (done && !claimed) return 'completed'
|
|
if (hasGuideProgress(key)) return 'in_progress'
|
|
return 'not_started'
|
|
}
|
|
|
|
function getStatusText(status, progress) {
|
|
if (status === 'in_progress') {
|
|
return `${progress.completed}/${progress.total} 步骤`
|
|
}
|
|
const map = {
|
|
not_started: '未开始',
|
|
completed: '已完成',
|
|
reward_claimed: '已领取'
|
|
}
|
|
return map[status] || '未开始'
|
|
}
|
|
|
|
function getButtonText(status) {
|
|
const map = {
|
|
not_started: '开始',
|
|
in_progress: '继续',
|
|
completed: '领取奖励',
|
|
reward_claimed: '已领取'
|
|
}
|
|
return map[status] || '开始'
|
|
}
|
|
|
|
function getButtonType(status) {
|
|
const map = {
|
|
not_started: 'start',
|
|
in_progress: 'continue',
|
|
completed: 'claim',
|
|
reward_claimed: 'claimed'
|
|
}
|
|
return map[status] || 'start'
|
|
}
|
|
|
|
// 开始引导
|
|
function handleStartGuide(key) {
|
|
console.log('[GuideModal] handleStartGuide:', key)
|
|
clearSubStepProgress(key)
|
|
resetGuide(key)
|
|
const targetPage = getStepPage(key, 0)
|
|
|
|
if (targetPage) {
|
|
emit('close')
|
|
uni.navigateTo({
|
|
url: targetPage + '?guide_key=' + key + '&guide_step=0'
|
|
})
|
|
}
|
|
}
|
|
|
|
// 继续引导
|
|
function handleContinueGuide(key) {
|
|
console.log('[GuideModal] handleContinueGuide:', key)
|
|
const resumeStep = getNextIncompleteStep(key)
|
|
const targetPage = getStepPage(key, resumeStep)
|
|
|
|
if (targetPage) {
|
|
emit('close')
|
|
uni.navigateTo({
|
|
url: targetPage + '?guide_key=' + key + '&guide_step=' + resumeStep
|
|
})
|
|
}
|
|
}
|
|
|
|
// 完成引导并同步后端
|
|
async function completeGuideAndSync(key) {
|
|
try {
|
|
markGuideDone(key)
|
|
await completeGuide(key, onboardingStages)
|
|
console.log('[GuideModal] completeGuideAndSync success:', key)
|
|
} catch (err) {
|
|
console.error('[GuideModal] completeGuideAndSync error:', err)
|
|
}
|
|
}
|
|
|
|
// 检查并同步所有完成的引导到后端
|
|
async function checkAndSyncCompletedGuides() {
|
|
const rawList = getGuideStatusList()
|
|
for (const item of rawList) {
|
|
if (item.done && !item.claimed) {
|
|
await completeGuideAndSync(item.key)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 领取奖励
|
|
async function handleClaimReward(key) {
|
|
try {
|
|
const config = getGuideConfig(key)
|
|
if (!config) return
|
|
|
|
// 从 onboardingStages 找到对应 stage
|
|
let stageNum = -1
|
|
for (const s of onboardingStages) {
|
|
if (s.required_task_keys.includes(key)) {
|
|
stageNum = s.stage
|
|
break
|
|
}
|
|
}
|
|
|
|
if (stageNum >= 0) {
|
|
const res = await claimOnboardingReward(stageNum)
|
|
// 更新本地存储的余额并通知 Header 组件
|
|
if (res.data?.crystal_balance !== undefined) {
|
|
try {
|
|
const userStr = uni.getStorageSync('user')
|
|
if (userStr) {
|
|
const user = JSON.parse(userStr)
|
|
user.crystal_balance = parseInt(res.data.crystal_balance)
|
|
uni.setStorageSync('user', JSON.stringify(user))
|
|
}
|
|
} catch (e) {
|
|
console.error('更新本地存储失败:', e)
|
|
}
|
|
uni.$emit('balanceUpdated', { crystal_balance: res.data.crystal_balance, experience: res.data.experience })
|
|
}
|
|
}
|
|
|
|
// 本地标记已领取
|
|
claimGuideReward(key)
|
|
refreshList()
|
|
emit('updated')
|
|
} catch (err) {
|
|
console.error('handleClaimReward error:', err)
|
|
uni.showToast({ title: '领取失败', icon: 'none' })
|
|
}
|
|
}
|
|
|
|
// 初始化时同步后端
|
|
async function initBackend() {
|
|
try {
|
|
loading.value = true
|
|
|
|
const res = await getOnboardingStatus()
|
|
const data = res.data || {}
|
|
|
|
if (!data.stages || data.stages.length === 0) {
|
|
await completeGuide('init', onboardingStages)
|
|
} else {
|
|
for (const stage of data.stages) {
|
|
if (stage.allTasksCompleted && stage.required_task_keys) {
|
|
for (const taskKey of stage.required_task_keys) {
|
|
if (!markGuideDone(taskKey)) {
|
|
console.log('[GuideModal] 从后端同步任务完成状态:', taskKey)
|
|
markGuideDone(taskKey)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
refreshList()
|
|
await checkAndSyncCompletedGuides()
|
|
} catch (err) {
|
|
console.error('initBackend error:', err)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 阻止移动事件
|
|
const handlePreventMove = (e) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
return false
|
|
}
|
|
|
|
// 关闭弹窗
|
|
const handleClose = () => {
|
|
emit('close')
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.guide-modal-wrapper {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 9999;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
overflow: hidden;
|
|
touch-action: none;
|
|
-webkit-overflow-scrolling: auto;
|
|
}
|
|
|
|
.modal-mask {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.6);
|
|
z-index: 1;
|
|
touch-action: none;
|
|
-webkit-overflow-scrolling: auto;
|
|
overscroll-behavior: contain;
|
|
}
|
|
|
|
.modal-container {
|
|
position: relative;
|
|
width: 748rpx;
|
|
min-height: 66vh;
|
|
border-radius: 40rpx;
|
|
overflow: hidden;
|
|
z-index: 2;
|
|
touch-action: pan-y;
|
|
-webkit-overflow-scrolling: touch;
|
|
overscroll-behavior: contain;
|
|
}
|
|
|
|
.modal-background {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 0;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.modal-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 1;
|
|
background: #00000021;
|
|
}
|
|
|
|
.modal-content {
|
|
position: relative;
|
|
z-index: 2;
|
|
padding: 64rpx;
|
|
display: flex;
|
|
flex-direction: column;
|
|
max-height: 85vh;
|
|
overflow: hidden;
|
|
touch-action: pan-y;
|
|
}
|
|
|
|
/* 顶部区域 */
|
|
.modal-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 30rpx;
|
|
position: relative;
|
|
}
|
|
|
|
/* 返回按钮 */
|
|
.back-button {
|
|
position: absolute;
|
|
left: 0;
|
|
width: 60rpx;
|
|
height: 60rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 10;
|
|
}
|
|
|
|
.back-icon {
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
}
|
|
|
|
/* 标题 */
|
|
.modal-title {
|
|
flex: 1;
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
color: #fff;
|
|
text-align: center;
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
text-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
/* 列表区域 */
|
|
.modal-body {
|
|
flex: 1;
|
|
max-height: 800rpx;
|
|
overflow-y: auto;
|
|
margin-bottom: 20rpx;
|
|
touch-action: pan-y;
|
|
-webkit-overflow-scrolling: touch;
|
|
overscroll-behavior: contain;
|
|
}
|
|
|
|
.guide-item {
|
|
background: linear-gradient(45deg, rgba(255, 136, 109, 0.6) 0%, rgba(202, 88, 180, 0.6) 33%, rgba(235, 230, 178, 0.6) 100%);
|
|
border-radius: 24rpx;
|
|
padding: 16rpx 30rpx;
|
|
margin-bottom: 16rpx;
|
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.guide-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.guide-item.in-progress {
|
|
border-left: 4rpx solid #4a90e2;
|
|
}
|
|
|
|
.guide-item-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.guide-status-badge {
|
|
padding: 4rpx 12rpx;
|
|
border-radius: 8rpx;
|
|
font-size: 22rpx;
|
|
margin-right: 12rpx;
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
}
|
|
|
|
.guide-status-badge.not_started {
|
|
background: rgba(255, 255, 255, 0.3);
|
|
border: 2rpx solid rgba(255, 255, 255, 0.4);
|
|
color: #fff;
|
|
}
|
|
|
|
.guide-status-badge.in_progress {
|
|
background: rgba(74, 144, 226, 0.6);
|
|
border: 2rpx solid rgba(255, 255, 255, 0.5);
|
|
color: #fff;
|
|
}
|
|
|
|
.guide-status-badge.completed {
|
|
background: linear-gradient(135deg, rgba(144, 238, 144, 0.6) 0%, rgba(60, 179, 113, 0.6) 100%);
|
|
border: 2rpx solid rgba(255, 255, 255, 0.5);
|
|
color: #fff;
|
|
}
|
|
|
|
.guide-status-badge.reward_claimed {
|
|
background: rgba(150, 150, 150, 0.5);
|
|
border: 2rpx solid rgba(150, 150, 150, 0.6);
|
|
color: #fff;
|
|
}
|
|
|
|
.guide-name {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: #fff;
|
|
flex: 1;
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.guide-item-body {
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.guide-desc {
|
|
font-size: 24rpx;
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.guide-progress {
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.progress-bar {
|
|
height: 8rpx;
|
|
background: rgba(255, 255, 255, 0.3);
|
|
border-radius: 4rpx;
|
|
overflow: hidden;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
|
|
border-radius: 4rpx;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.progress-text {
|
|
font-size: 22rpx;
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.guide-item-footer {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.guide-btn {
|
|
min-width: 120rpx;
|
|
width: 120rpx;
|
|
height: 50rpx;
|
|
padding: 0;
|
|
color: #fff;
|
|
border-radius: 25rpx;
|
|
font-size: 24rpx;
|
|
font-weight: bold;
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.start-btn {
|
|
background: linear-gradient(to bottom right, #F0E4B1 0%, #F08399 50%, #B94E73 100%);
|
|
box-shadow:
|
|
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
|
|
0 2rpx 6rpx rgba(255, 143, 158, 0.15),
|
|
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4),
|
|
inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
|
border: 2rpx solid rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.continue-btn {
|
|
background: linear-gradient(to bottom right, #F0E4B1 0%, #F08399 50%, #B94E73 100%);
|
|
box-shadow:
|
|
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
|
|
0 2rpx 6rpx rgba(255, 143, 158, 0.15),
|
|
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4),
|
|
inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
|
border: 2rpx solid rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.claim-btn {
|
|
background: linear-gradient(to bottom right, #F0E4B1 0%, #F08399 50%, #B94E73 100%);
|
|
box-shadow:
|
|
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
|
|
0 2rpx 6rpx rgba(255, 143, 158, 0.15),
|
|
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4),
|
|
inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
|
border: 2rpx solid rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.disabled-btn {
|
|
background: rgba(150, 150, 150, 0.5);
|
|
border: 2rpx solid rgba(150, 150, 150, 0.6);
|
|
box-shadow: none;
|
|
color: #fff;
|
|
}
|
|
|
|
/* 底部统计 */
|
|
.modal-footer {
|
|
padding: 24rpx 0 0;
|
|
border-top: 2rpx solid rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
.footer-stats {
|
|
font-size: 28rpx;
|
|
color: #fff;
|
|
text-align: center;
|
|
margin-bottom: 8rpx;
|
|
font-weight: bold;
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.footer-claim-tip {
|
|
font-size: 26rpx;
|
|
color: #FFD700;
|
|
text-align: center;
|
|
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
|
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
|
}
|
|
</style>
|