Files
hhrs/pages/rights/rights.vue
T

1016 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page" :class="{ 'page-auth': status === 'auth' }">
<!-- xuchao: 顶部导航(返回+页面名称,认证状态使用) -->
<view class="nav-bar" v-if="status === 'auth'">
<view class="nav-back" @click="goBack">
<u-icon name="arrow-left" color="#1a1818" size="40"></u-icon>
</view>
<text class="nav-title">权益资格认证</text>
</view>
<!-- 返回按钮(顶部,非auth状态) -->
<view class="back-btn" :class="{ 'back-btn--black': status === 'noWin' }" @click="goBack" v-if="status !== 'auth'">
<u-icon name="arrow-left" :color="status === 'noWin' ? '#000000' : '#ffffff'" size="40"></u-icon>
<text class="back-text">返回</text>
</view>
<!-- 状态1: 权益资格认证 -->
<view v-if="status === 'auth'" class="auth-container">
<view class="section-title">
<view class="title-bar"></view>
<text class="title-text">权益资格认证</text>
</view>
<view class="form-area">
<view class="form-item">
<text class="form-label required">真实姓名</text>
<input class="form-input" v-model="form.realName" placeholder="请输入真实姓名" />
</view>
<view class="form-item">
<text class="form-label required">手机号码</text>
<text class="form-value phone-value">{{ form.phone }}</text>
</view>
<view class="form-item" @click="showIdTypePicker = true">
<text class="form-label required">证件类型</text>
<text class="form-value">{{ form.idType }}</text>
<text class="form-arrow">&#xe602;</text>
</view>
<view class="form-item">
<text class="form-label required">证件号码</text>
<input class="form-input" v-model="form.idNumber" placeholder="请输入真实证件号码" />
</view>
</view>
<view class="auth-btn" @click="onAuth">开始认证</view>
<view class="tips-section">
<view class="section-title">
<view class="title-bar"></view>
<text class="title-text">温馨提示</text>
</view>
<view class="tips-list">
<text class="tip-item">1. 请输入真实的身份信息用来进行活动权益资格认证</text>
<text class="tip-item">2. 认证通过后系统会显示出您的所获得的权益信息</text>
<text class="tip-item">3. 手机号码为您登录的手机,无法修改。若号码对,请更换登录手机。</text>
</view>
</view>
</view>
<!-- 状态2: 未中奖 -->
<view v-if="status === 'noWin'" class="empty-container">
<image class="empty-img" src="https://aliyunoss.hn12301.net/hhrs/hhrs_wzj.png" mode="widthFix" />
<text class="empty-text">您暂未中奖</text>
</view>
<!-- 状态3: 权益信息 -->
<view v-if="status === 'info'">
<!-- 蓝色头部横幅 -->
<view style="background: #fff;">
<view class="banner-area">
<text class="banner-title">恭喜您!获得怀化市社保卡权益包</text>
<view class="banner-expire" v-if="expiresTime">
<text class="expire-icon">!</text>
<text class="expire-text">{{ expiresTime }}</text>
<text class="expire-label">到期</text>
</view>
</view>
<!-- 权益统计卡片 -->
<view class="stats-card">
<view class="stats-item">
<text class="stats-label">总权益价值</text>
<view class="stats-value-row">
<text class="stats-currency">¥</text>
<text class="stats-number">{{ totalValueText }}</text>
<text class="stats-unit">元</text>
</view>
</view>
<view class="stats-divider"></view>
<view class="stats-item">
<text class="stats-label">可用权益数</text>
<view class="stats-value-row">
<text class="stats-number-large">{{ rightsCount }}</text>
<text class="stats-unit">个</text>
</view>
</view>
</view>
<!-- Tab 切换 -->
<view class="tab-bar">
<view v-for="(tab, index) in tabs" :key="index" class="tab-item"
:class="{ active: currentTab === index }" @click="switchTab(index)">
<text class="tab-text">{{ tab }}</text>
</view>
</view>
</view>
<!-- 搜索栏 -->
<view class="search-area" v-if="currentTab==0">
<view class="search-bar">
<u-icon name="search" color="#cccccc" size="24"></u-icon>
<input class="search-input" v-model="keyword" placeholder="搜索权益商家" @confirm="onSearch" />
</view>
</view>
<!-- 权益列表 -->
<scroll-view class="list-area" scroll-y @scrolltolower="loadMore" :lower-threshold="100"
v-if="currentTab==0">
<view class="rights-card" v-for="item in rightsList" :key="item.ruleId" @click="goDetail(item)">
<image class="card-img" :src="item.image" mode="aspectFill" />
<view class="card-info">
<view class="card-name">{{ item.name }}</view>
<view class="card-category">{{ item.category }}</view>
<view class="card-address">{{ item.address }}</view>
</view>
<view class="card-distance" v-if="item.distance !== null">
<u-icon name="map" color="#999999" size="24"></u-icon>
<text
class="distance-text">{{ item.distance < 1 ? Math.round(item.distance * 1000) + 'm' : Math.round(item.distance) + 'km' }}</text>
</view>
</view>
<view class="empty-state" v-if="rightsList.length === 0 && !loading">
<image class="empty-state-img" src="https://zhihuiyou.oss-cn-shenzhen.aliyuncs.com/hhrs/hhrs_wzj.png" mode="widthFix"></image>
<text class="empty-state-text">暂无内容</text>
</view>
</scroll-view>
<scroll-view class="list-area" scroll-y @scrolltolower="loadAppointmentMore" :lower-threshold="100"
v-if="currentTab==1">
<view class="rights-card" style="margin-top: 24rpx;flex-direction: column;" v-for="item in appointmentList"
:key="item.id" >
<view style="width: 654rpx;display: flex;justify-content: space-between;">
<text>{{ item.resourceName }}</text><text style="color: #34C759;">已预约</text></view>
<view style="font-size: 24rpx;color: #727272;margin-top: 24rpx;">预约游玩日期:{{ item.appTime.split(' ')[0] }}
<text v-if="item.timeName">({{ item.timeName }})</text></view>
</view>
<view class="empty-state" v-if="appointmentList.length === 0 && !appointmentLoading">
<image class="empty-state-img" src="https://zhihuiyou.oss-cn-shenzhen.aliyuncs.com/hhrs/hhrs_wzj.png" mode="widthFix"></image>
<text class="empty-state-text">暂无内容</text>
</view>
</scroll-view>
<scroll-view class="list-area" scroll-y @scrolltolower="loadCheckMore" :lower-threshold="100"
v-if="currentTab==2">
<view class="rights-card" style="margin-top: 24rpx;flex-direction: column;" v-for="item in checkList"
:key="item.id" >
<view style="width: 654rpx;display: flex;justify-content: space-between;">
<text>{{ item.resourceName }}</text><text style="color: #FF383C;">已使用</text></view>
<view style="font-size: 24rpx;color: #727272;margin-top: 24rpx;">核销时间:{{ item.checkTime }}</view>
</view>
<view class="empty-state" v-if="checkList.length === 0 && !checkLoading">
<image class="empty-state-img" src="https://zhihuiyou.oss-cn-shenzhen.aliyuncs.com/hhrs/hhrs_wzj.png" mode="widthFix"></image>
<text class="empty-state-text">暂无内容</text>
</view>
<view class="loading" v-if="checkLoading">
<text class="loading-text">加载中...</text>
</view>
<view class="no-more" v-else-if="checkList.length >= checkTotal && checkList.length > 0">
<text class="no-more-text">没有更多了</text>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
status: 'auth',
// xuchao: 权益概览三字段,首屏用缓存兜底,随后由服务端复查刷新
expiresTime: uni.getStorageSync('expiresTime') || '',
rightsCount: uni.getStorageSync('rightsCount') || 0,
totalValueFen: uni.getStorageSync('totalValueFen') || 0,
form: {
realName: '',
phone: '',
idType: '居民身份证',
idNumber: ''
},
showIdTypePicker: false,
tabs: ['待使用', '已预约', '已使用'],
currentTab: 0,
keyword: '',
rightsList: [],
pageNo: 1,
pageSize: 1000,
total: 0,
lng: '',
lat: '',
loading: false,
appointmentList: [],
appointmentPageNo: 1,
appointmentTotal: 0,
appointmentLoading: false,
checkList: [],
checkPageNo: 1,
checkTotal: 0,
checkLoading: false
}
},
computed: {
// xuchao: 总权益价值分转元,整除去小数,否则保留两位
totalValueText() {
const yuan = this.totalValueFen / 100
return Number.isInteger(yuan) ? String(yuan) : yuan.toFixed(2)
}
},
onLoad(options) {
if (options.status) {
this.status = options.status
}
this.form.phone = uni.getStorageSync('phone') || ''
const loc = uni.getStorageSync('lng') && uni.getStorageSync('lat') ? {
lng: uni.getStorageSync('lng'),
lat: uni.getStorageSync('lat')
} :
null
if (loc) {
this.lng = loc.lng
this.lat = loc.lat
}
this.checkAuthResult()
// xuchao: 权益状态会变化,缓存只作首屏展示,进入页面一律向服务端复查最新状态
this.refreshStatus()
if (this.status === 'info') {
this.loadRightsList()
}
},
methods: {
// xuchao: 缓存的权益状态可能过期(中奖/权益包会变化),每次进页面仅凭手机号向服务端
// 复查最新状态并覆盖缓存(不带证件号,避免触发被动认证)
refreshStatus() {
// xuchao: 人脸认证回调场景由 checkAuthResult 负责查询,跳过避免重复请求
try {
if (new URL(window.location.href).searchParams.get('response')) return
} catch (e) {
return
}
// xuchao: 用户主动发起过认证流程时,取消后应停留在认证页,不自动恢复
if (this.status === 'auth' && uni.getStorageSync('authFlowStarted')) return
const phone = uni.getStorageSync('phone')
if (!phone) return
this.$u.api.getEligibility({
phone: phone
}).then(res => {
if (res.errcode !== 0 || !res.data) return
this.applyEligibility(res.data)
// xuchao: 服务端已认证则清除取消标记,后续按真实状态展示
if (res.data.isAuth) uni.removeStorageSync('authFlowStarted')
const newStatus = res.data.isAuth ? (res.data.hasWin ? 'info' : 'noWin') : 'auth'
const prevStatus = this.status
this.status = newStatus
// xuchao: 状态刷新为权益页时补拉权益列表,避免与首屏加载重复
if (newStatus === 'info' && prevStatus !== 'info') {
this.loadRightsList()
}
})
},
// xuchao: 资格查询结果统一写入缓存并回填页面(到期时间/总权益价值/可用权益数)
applyEligibility(data) {
uni.setStorageSync('isAuth', data.isAuth)
uni.setStorageSync('hasWin', data.hasWin)
uni.setStorageSync('cardNumber', data.cardNumber)
uni.setStorageSync('expiresTime', data.expiresTime)
uni.setStorageSync('rightsCount', data.rightsCount || 0)
uni.setStorageSync('totalValueFen', data.totalValueFen || 0)
this.expiresTime = data.expiresTime || ''
this.rightsCount = data.rightsCount || 0
this.totalValueFen = data.totalValueFen || 0
},
// xuchao: 认证取消/未通过:清理旧认证缓存并标记流程已发起,取消后应停留认证页
markAuthCanceled() {
uni.removeStorageSync('isAuth')
uni.removeStorageSync('hasWin')
uni.removeStorageSync('cardNumber')
uni.removeStorageSync('expiresTime')
uni.removeStorageSync('rightsCount')
uni.removeStorageSync('totalValueFen')
uni.setStorageSync('authFlowStarted', true)
},
checkAuthResult() {
const url = new URL(window.location.href)
let responseStr = url.searchParams.get('response')
console.log('responseStr:', responseStr)
if (!responseStr) return
let response
try {
let parms = JSON.parse(decodeURIComponent(responseStr))
console.log('parms:', parms)
response = typeof parms === 'string' ? JSON.parse(parms) : parms
console.log('response:', response)
} catch (e) {
try {
response = JSON.parse(responseStr)
} catch (e2) {
return
}
}
const code = response.code
const certifyId = response.extInfo ? response.extInfo.certifyId : ''
console.log('code:', code, 'certifyId:', certifyId)
if (code == 1000 && certifyId) {
this.$u.api.describeFaceVerify({
certifyId: certifyId
}).then(res => {
console.log('describeFaceVerify res:', res)
if (res.errcode === 0 && res.data.body && res.data.body.resultObject) {
const verifyResult = res.data.body.resultObject
console.log('verifyResult:', verifyResult)
if (String(verifyResult.passed) === 'T' || String(verifyResult.Passed) === 'T') {
const phone = uni.getStorageSync('phone') || ''
const name = uni.getStorageSync('authName') || ''
const identityNo = uni.getStorageSync('authIdNo') || ''
this.$u.api.getEligibility({
phone: phone,
identityNo: identityNo,
name: name
}).then(eRes => {
console.log('eligibility res:', eRes)
if (eRes.errcode === 0) {
this.applyEligibility(eRes.data)
// xuchao: 认证成功,清除流程标记
uni.removeStorageSync('authFlowStarted')
if (eRes.data.isAuth) {
this.status = eRes.data.hasWin ? 'info' : 'noWin'
if (this.status === 'info') {
this.loadRightsList()
}
}
}
})
} else {
// xuchao: 实名未通过视为取消认证,清理缓存并标记
this.markAuthCanceled()
uni.showToast({
title: '认证未通过',
icon: 'none'
})
}
} else {
uni.showToast({
title: '认证结果查询失败',
icon: 'none'
})
}
}).catch(() => {
uni.showToast({
title: '认证结果查询失败',
icon: 'none'
})
})
} else {
// xuchao: 未返回认证回调视为取消认证,清理缓存并标记
this.markAuthCanceled()
uni.showToast({
title: '认证未通过',
icon: 'none'
})
}
},
loadAliyunSDK() {
return new Promise((resolve, reject) => {
if (window.getMetaInfo) {
resolve()
return
}
const script = document.createElement('script')
script.src = 'https://o.alicdn.com/yd-cloudauth/cloudauth-cdn/jsvm_all.js'
script.onload = () => resolve()
script.onerror = () => reject(new Error('加载阿里云SDK失败'))
document.head.appendChild(script)
})
},
onAuth() {
if (!this.form.realName) {
uni.showToast({
title: '请输入真实姓名',
icon: 'none'
})
return
}
if (!this.form.idNumber) {
uni.showToast({
title: '请输入证件号码',
icon: 'none'
})
return
}
uni.setStorageSync('authName', this.form.realName)
uni.setStorageSync('authIdNo', this.form.idNumber)
// xuchao: 标记已发起认证流程,取消后停留在认证页,不自动恢复
uni.setStorageSync('authFlowStarted', true)
this.loadAliyunSDK().then(() => {
const metaInfo = JSON.stringify(window.getMetaInfo())
const returnUrl = window.location.origin + window.location.pathname +
'?response=%7B%7D#/pages/rights/rights?status=auth'
this.$u.api.initFaceVerify({
certName: this.form.realName,
certNo: this.form.idNumber,
metaInfo: metaInfo,
returnUrl: returnUrl
}).then(res => {
if (res.errcode === 0 && res.data.body && res.data.body.resultObject && res.data
.body.resultObject.certifyUrl) {
window.location.href = res.data.body.resultObject.certifyUrl
} else {
uni.showToast({
title: res.errmsg || '认证初始化失败',
icon: 'none'
})
}
}).catch(() => {
uni.showToast({
title: '认证初始化失败',
icon: 'none'
})
})
}).catch(() => {
uni.showToast({
title: '加载认证组件失败',
icon: 'none'
})
})
},
loadRightsList() {
const cardNumber = uni.getStorageSync('cardNumber') || ''
this.fetchRightsList(cardNumber)
},
fetchRightsList(cardNumber) {
if (this.loading) return
this.loading = true
this.$u.api.getRightsList({
pageNo: this.pageNo,
pageSize: this.pageSize,
keyword: this.keyword,
lng: this.lng,
lat: this.lat,
cardNumber: cardNumber
}).then(res => {
if (res.errcode === 0 && res.data) {
const list = res.data.list || []
if (this.pageNo === 1) {
this.rightsList = list
} else {
this.rightsList = this.rightsList.concat(list)
}
this.total = res.data.total || 0
}
}).finally(() => {
this.loading = false
})
},
loadMore() {
if (this.rightsList.length < this.total && !this.loading) {
this.pageNo++
this.loadRightsList()
}
},
switchTab(index) {
this.currentTab = index
if (index === 1 && this.appointmentList.length === 0) {
this.appointmentPageNo = 1
this.loadAppointmentList()
}
if (index === 2 && this.checkList.length === 0) {
this.checkPageNo = 1
this.loadCheckList()
}
},
loadAppointmentList() {
const cardNumber = uni.getStorageSync('cardNumber') || ''
if (this.appointmentLoading) return
this.appointmentLoading = true
this.$u.api.getAppointmentList({
pageNo: this.appointmentPageNo,
pageSize: this.pageSize,
cardNumber: cardNumber
}).then(res => {
if (res.errcode === 0 && res.data) {
const list = res.data.list || []
if (this.appointmentPageNo === 1) {
this.appointmentList = list
} else {
this.appointmentList = this.appointmentList.concat(list)
}
this.appointmentTotal = res.data.total || 0
}
}).finally(() => {
this.appointmentLoading = false
})
},
loadAppointmentMore() {
if (this.appointmentList.length < this.appointmentTotal && !this.appointmentLoading) {
this.appointmentPageNo++
this.loadAppointmentList()
}
},
loadCheckList() {
const cardNumber = uni.getStorageSync('cardNumber') || ''
if (this.checkLoading) return
this.checkLoading = true
this.$u.api.getCheckList({
pageNo: this.checkPageNo,
pageSize: this.pageSize,
cardNumber: cardNumber
}).then(res => {
if (res.errcode === 0 && res.data) {
const list = res.data.list || []
if (this.checkPageNo === 1) {
this.checkList = list
} else {
this.checkList = this.checkList.concat(list)
}
this.checkTotal = res.data.total || 0
}
}).finally(() => {
this.checkLoading = false
})
},
loadCheckMore() {
if (this.checkList.length < this.checkTotal && !this.checkLoading) {
this.checkPageNo++
this.loadCheckList()
}
},
onSearch() {
this.pageNo = 1
this.loadRightsList()
},
goDetail(item) {
uni.navigateTo({
url: '/pages/rights/detail?id=' + item.ruleId
})
},
goBack() {
// xuchao: 直接通过链接进入(无历史栈)时回到首页
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack()
} else {
uni.reLaunch({ url: '/pages/index/index' })
}
}
}
}
</script>
<style>
page {
background-color: #f2f2f7;
}
</style>
<style scoped lang="less">
.page-auth {
background-color: #ffffff;
}
/* 认证表单 */
.auth-container {
min-height: 100vh;
padding: 16px;
}
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.title-bar {
width: 4px;
height: 16px;
background-color: #0088ff;
border-radius: 2px;
margin-right: 8px;
}
.title-text {
font-size: 16px;
font-weight: 600;
color: #1a1818;
}
.form-area {
background-color: #ffffff;
border-radius: 8px;
padding: 0 16px;
}
.form-item {
display: flex;
align-items: center;
height: 64px;
width: 100%;
border-bottom: 1px solid #f0f0f0;
position: relative;
}
.form-label {
font-size: 14px;
color: #333333;
width: 80px;
flex-shrink: 0;
}
.form-label.required::before {
content: '*';
color: #ff4d4f;
margin-right: 4px;
}
.form-input {
flex: 1;
font-size: 14px;
color: #333333;
}
.form-value {
flex: 1;
font-size: 14px;
color: #333333;
}
.phone-value {
color: #999999;
}
.form-arrow {
font-size: 14px;
color: #cccccc;
}
.auth-btn {
margin: 24px 0;
background-color: #0088ff;
color: #ffffff;
text-align: center;
font-size: 16px;
font-weight: 500;
height: 48px;
line-height: 48px;
border-radius: 24px;
}
.tips-section {
margin-top: 8px;
}
.tips-list {
display: flex;
flex-direction: column;
gap: 12px;
padding: 0 4px;
}
.tip-item {
font-size: 13px;
color: #ff4d4f;
line-height: 1.6;
}
/* 未中奖空状态 */
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 160px;
}
.empty-img {
width: 200px;
}
.empty-text {
font-size: 18px;
color: #999999;
margin-top: 24px;
}
/* 权益信息 - 蓝色横幅 */
.banner-area {
background-color: #0088ff;
padding: 80px 16px 96px;
border-radius: 0 0 50px 50px;
}
.banner-title {
font-size: 24px;
color: #ffffff;
font-weight: 700;
display: block;
text-align: center;
margin-bottom: 12px;
}
.banner-expire {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
}
.expire-icon {
width: 18px;
height: 18px;
background-color: #ffffff;
color: #0088ff;
border-radius: 50%;
text-align: center;
line-height: 18px;
font-size: 12px;
font-weight: 700;
}
.expire-text {
font-size: 24px;
color: #ffffff;
font-weight: 600;
}
.expire-label {
font-size: 24px;
color: #ffffff;
}
/* 统计卡片 */
.stats-card {
display: flex;
align-items: center;
background: #FFFFFF;
margin: -60px 12px 0;
border-radius: 10px;
padding: 16px 24px;
box-shadow: 0px 4px 4px 0px #00000019;
position: relative;
z-index: 1;
}
.stats-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.stats-label {
font-size: 12px;
color: #999999;
margin-bottom: 8px;
}
.stats-value-row {
display: flex;
align-items: baseline;
}
.stats-currency {
font-size: 14px;
color: #1a1818;
font-weight: 600;
}
.stats-number {
font-size: 28px;
color: #1a1818;
font-weight: 700;
}
.stats-number-large {
font-size: 28px;
color: #1a1818;
font-weight: 700;
}
.stats-unit {
font-size: 12px;
color: #999999;
margin-left: 2px;
}
.stats-divider {
width: 1px;
height: 36px;
background-color: #eeeeee;
}
/* Tab 切换 */
.tab-bar {
display: flex;
background-color: #ffffff;
margin-top: 12px;
padding: 0 16px;
}
.tab-item {
flex: 1;
text-align: center;
padding: 12px 0;
position: relative;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 24px;
height: 3px;
background-color: #0088ff;
border-radius: 2px;
}
.tab-text {
font-size: 14px;
color: #999999;
}
.tab-item.active .tab-text {
color: #0088ff;
font-weight: 600;
}
/* 搜索栏 */
.search-area {
padding: 12px;
}
.search-bar {
display: flex;
align-items: center;
height: 36px;
background-color: #ffffff;
border-radius: 18px;
padding: 0 12px;
gap: 8px;
}
.search-input {
flex: 1;
font-size: 14px;
color: #333333;
}
/* 权益列表 */
.list-area {
width: 750rpx;
display: flex;
flex-direction: column;
gap: 10px;
}
.rights-card {
width: 702rpx;
background-color: #fff;
margin-left: 24rpx;
padding: 24rpx;
display: flex;
position: relative;
margin-bottom: 24rpx;
}
.card-img {
width: 150rpx;
height: 150rpx;
border-radius: 6px;
flex-shrink: 0;
}
.card-info {
width: 490rpx;
margin-left: 14rpx;
display: flex;
flex-direction: column;
height: 150rpx;
justify-content: space-between;
}
.card-name {
font-size: 15px;
font-weight: 500;
color: #1a1818;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-category {
font-size: 13px;
color: #999999;
margin-top: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-address {
width: 300rpx;
font-size: 13px;
color: #999999;
margin-top: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-distance {
display: flex;
align-items: center;
gap: 2px;
flex-shrink: 0;
position: absolute;
bottom: 24rpx;
right: 24rpx;
}
.distance-text {
font-size: 12px;
color: #999999;
}
.loading {
text-align: center;
padding: 16px 0;
}
.loading-text {
font-size: 14px;
color: #999999;
}
.no-more {
text-align: center;
padding: 16px 0;
}
.no-more-text {
font-size: 14px;
color: #999999;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 80px;
}
.empty-state-img {
width: 200px;
}
.empty-state-text {
font-size: 16px;
color: #999999;
margin-top: 16px;
}
/* 返回按钮 */
.back-btn {
position: fixed;
top: 24px;
left: 24px;
display: flex;
align-items: center;
gap: 2px;
z-index: 10;
}
.back-text {
font-size: 14px;
color: #ffffff;
}
/* xuchao: noWin 状态(无中奖空态页)返回按钮改黑色 */
.back-btn--black .back-text {
color: #000000;
}
/* xuchao: 顶部返回导航条(auth状态) */
.nav-bar {
display: flex;
align-items: center;
height: 56px;
background-color: #ffffff;
border-bottom: 1px solid #f0f0f0;
position: relative;
}
.nav-back {
position: absolute;
left: 12px;
top: 0;
bottom: 0;
display: flex;
align-items: center;
}
.nav-title {
flex: 1;
text-align: center;
font-size: 17px;
font-weight: 600;
color: #1a1818;
padding: 0 56px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>