1351 lines
28 KiB
Vue
1351 lines
28 KiB
Vue
<template>
|
|
<view class="rules-page theme-transition" :style="{ backgroundColor: themeConfig.bgColor }">
|
|
<scroll-view class="rules-content" scroll-y>
|
|
<view class="page-header" :style="{ background: `linear-gradient(135deg, ${themeConfig.primaryColor} 0%, ${themeConfig.secondaryColor} 100%)` }">
|
|
<text class="page-title">{{ pageData.title || '成长规则' }}</text>
|
|
<text class="page-subtitle" v-if="pageData.subtitle">{{ pageData.subtitle }}</text>
|
|
</view>
|
|
|
|
<view class="content-wrapper">
|
|
<view v-for="(section, index) in pageData.sections" :key="index" class="section-card" :style="{ backgroundColor: themeConfig.cardBgColor }">
|
|
<view class="section-header" v-if="section.title">
|
|
<view class="section-icon-wrap" :style="{ background: `linear-gradient(135deg, ${themeConfig.primaryColor}15 0%, ${themeConfig.secondaryColor}10 100%)` }">
|
|
<FaIcon :icon="section.iconName || getSectionIcon(section.type)" :size="22" :color="themeConfig.primaryColor" />
|
|
</view>
|
|
<text class="section-title">{{ section.title }}</text>
|
|
</view>
|
|
<view class="section-content" v-if="section.content">
|
|
<text class="content-text">{{ section.content }}</text>
|
|
</view>
|
|
|
|
<!-- 等级系统 -->
|
|
<view v-if="section.type === 'level_system' && section.levels" class="level-section">
|
|
<view v-for="(level, lIndex) in section.levels" :key="lIndex" class="level-item">
|
|
<view class="level-badge-wrap">
|
|
<view class="level-badge" :style="{ background: `linear-gradient(135deg, ${level.color}, ${level.color}90)` }">
|
|
<FaIcon :icon="level.iconName || 'award'" :size="22" color="#fff" />
|
|
</view>
|
|
<text class="level-number">Lv.{{ level.level }}</text>
|
|
</view>
|
|
<view class="level-info">
|
|
<text class="level-title">{{ level.title }}</text>
|
|
<view class="level-privileges" v-if="level.privileges && level.privileges.length">
|
|
<text class="privilege-item" v-for="(priv, pIndex) in level.privileges" :key="pIndex">{{ priv }}</text>
|
|
</view>
|
|
<view class="level-progress">
|
|
<view class="progress-track" :style="{ backgroundColor: themeConfig.borderColor }">
|
|
<view class="progress-fill" :style="{
|
|
width: Math.min(100, (lIndex / (section.levels.length - 1)) * 100) + '%',
|
|
background: `linear-gradient(90deg, ${level.color}, ${level.color}70)`
|
|
}"></view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<text class="level-exp" :style="{ color: level.color }">{{ level.exp }} EXP</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 经验规则 -->
|
|
<view v-if="section.type === 'exp_rules'" class="exp-section">
|
|
<view class="exp-limit" v-if="section.limit" :style="{ background: `linear-gradient(135deg, ${themeConfig.primaryColor}15 0%, ${themeConfig.secondaryColor}10 100%)` }">
|
|
<FaIcon icon="star" :size="18" :color="themeConfig.warningColor || '#ffaa33'" />
|
|
<text class="limit-text">{{ section.limit }}</text>
|
|
</view>
|
|
<view class="exp-rules-list">
|
|
<view v-for="(rule, rIndex) in (section.rules || [])" :key="rIndex" class="exp-rule-card">
|
|
<view class="rule-icon-box" :style="{ background: getExpRuleBg(rIndex) }">
|
|
<FaIcon :icon="getExpRuleIcon(rIndex)" :size="22" :color="themeConfig.textPrimary" />
|
|
</view>
|
|
<view class="rule-content">
|
|
<view class="rule-header">
|
|
<text class="rule-title">{{ rule.desc }}</text>
|
|
<text class="rule-exp" v-if="rule.exp" :style="{ color: themeConfig.primaryColor }">+{{ rule.exp }} EXP</text>
|
|
</view>
|
|
<text class="rule-detail">{{ rule.detail }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 连续打卡加成 -->
|
|
<view v-if="section.type === 'streak_bonus'" class="streak-section">
|
|
<view v-if="section.formula" class="streak-formula">
|
|
<text class="formula-text">{{ section.formula }}</text>
|
|
</view>
|
|
<view class="streak-rules">
|
|
<view v-for="(streak, sIndex) in (section.rules || [])" :key="sIndex" class="streak-card">
|
|
<view class="streak-line">
|
|
<view class="line-dot" :style="{ background: streak.color }"></view>
|
|
<text class="streak-range">{{ streak.range }}</text>
|
|
</view>
|
|
<text class="streak-bonus" :style="{ color: streak.color }">{{ streak.bonus }}</text>
|
|
</view>
|
|
</view>
|
|
<view v-if="section.tip" class="streak-tip">
|
|
<text class="tip-text">{{ section.tip }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 新手保护 -->
|
|
<view v-if="section.type === 'protection'" class="protection-section">
|
|
<view class="protection-main">
|
|
<text class="main-title">{{ section.content }}</text>
|
|
<view class="bonus-tag" :style="{ background: `linear-gradient(135deg, ${themeConfig.primaryColor}20, ${themeConfig.secondaryColor}10)` }">
|
|
<text class="tag-text" :style="{ color: themeConfig.primaryColor }">{{ section.bonus }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="protection-detail">
|
|
<text class="detail-text">{{ section.detail }}</text>
|
|
</view>
|
|
<view class="protection-example">
|
|
<text class="example-text">{{ section.example }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 成就系统 -->
|
|
<view v-if="section.type === 'achievement_system'" class="achievement-section">
|
|
<view v-if="section.content" class="achievement-desc">
|
|
<text class="desc-text">{{ section.content }}</text>
|
|
</view>
|
|
<view v-if="section.rarityDesc" class="rarity-info">
|
|
<text class="rarity-text">{{ section.rarityDesc }}</text>
|
|
</view>
|
|
<view class="achievement-toggle" @click="toggleAchievements">
|
|
<view class="toggle-left">
|
|
<FaIcon icon="list" :size="18" :color="themeConfig.textSecondary" />
|
|
<text class="toggle-text">查看所有成就</text>
|
|
</view>
|
|
<text class="toggle-arrow" :class="{ expanded: showAchievements }">▼</text>
|
|
</view>
|
|
<view v-if="showAchievements" class="achievement-content">
|
|
<view class="category-tabs">
|
|
<view v-for="(cat, cIndex) in ['all', 'streak', 'task', 'mood', 'bill', 'review']" :key="cIndex"
|
|
class="category-tab"
|
|
:class="{ active: currentCategory === cat }"
|
|
@click="currentCategory = cat">
|
|
<text class="tab-emoji">{{ getCategoryEmoji(cat) }}</text>
|
|
<text class="tab-name">{{ getCatName(cat) }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="achievement-grid">
|
|
<view v-for="(achievement, aIndex) in getFilteredAchievements(section)" :key="achievement.id || aIndex" :class="['achievement-card', achievement.rarity && achievement.rarity.toLowerCase()]">
|
|
<view class="card-icon-wrap">
|
|
<view class="card-icon" :style="{ background: getCategoryColor(achievement.category) }">
|
|
<text class="card-emoji">{{ achievement.icon }}</text>
|
|
</view>
|
|
<view class="card-rarity-flag" v-if="achievement.rarity" :class="['rarity-flag', achievement.rarity.toLowerCase()]">
|
|
<text>{{ achievement.rarity }}</text>
|
|
</view>
|
|
</view>
|
|
<text class="card-desc">{{ achievement.desc || achievement.description }}</text>
|
|
<view class="card-footer">
|
|
<view class="cat-tag" :style="{ background: getCategoryBg(achievement.category), color: getCategoryColor(achievement.category) }">
|
|
<text class="cat-tag-text">{{ getCategoryName(achievement.category) }}</text>
|
|
</view>
|
|
<text class="exp-text">+{{ achievement.exp || achievement.expReward }} EXP</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 特权列表 -->
|
|
<view v-if="section.type === 'privileges' && section.privileges" class="privileges-section">
|
|
<view v-for="(privilege, pIndex) in section.privileges" :key="pIndex" class="privilege-card">
|
|
<FaIcon :icon="privilege.iconName || 'wand-magic-sparkles'" :size="22" :color="themeConfig.primaryColor" />
|
|
<view class="privilege-info">
|
|
<text class="privilege-name">{{ privilege.name || privilege.title }}</text>
|
|
<text class="privilege-desc" v-if="privilege.desc || privilege.description">{{ privilege.desc || privilege.description }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 技巧提示 -->
|
|
<view v-if="section.type === 'tips' && section.tips" class="tips-section">
|
|
<view v-for="(tip, tIndex) in section.tips" :key="tIndex" class="tip-card">
|
|
<view class="tip-icon-wrap" :style="{ background: `linear-gradient(135deg, ${getTipColor(tIndex)}30, ${getTipColor(tIndex)}15)` }">
|
|
<FaIcon icon="star" :size="18" :color="getTipColor(tIndex)" />
|
|
</view>
|
|
<view class="tip-content">
|
|
<text class="tip-text">{{ tip.content || tip.text || tip }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- FAQ问答 -->
|
|
<view v-if="section.type === 'faq' && section.questions" class="faq-section">
|
|
<view v-for="(qa, qIndex) in section.questions" :key="qIndex" class="faq-card">
|
|
<view class="faq-item" @click="toggleFaq(qIndex)">
|
|
<view class="faq-q">
|
|
<FaIcon :icon="expandedFaq === qIndex ? 'thumbtack' : 'circle-question'" :size="18" :color="expandedFaq === qIndex ? themeConfig.primaryColor : themeConfig.textSecondary" />
|
|
<text class="faq-q-text">{{ qa.Q || qa.q || qa.question }}</text>
|
|
</view>
|
|
<text class="faq-arrow" :class="{ expanded: expandedFaq === qIndex }">▼</text>
|
|
</view>
|
|
<view class="faq-a" :class="{ expanded: expandedFaq === qIndex }">
|
|
<view class="answer-content">
|
|
<text class="faq-a-text">{{ qa.A || qa.a || qa.answer }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="safe-area-bottom"></view>
|
|
</scroll-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { getThemeConfigFromStorage, THEME_PRESETS } from '@/utils/theme'
|
|
import { refreshNavBarTheme, forceApplyTabBarTheme } from '@/utils/themeGlobal'
|
|
import { getGrowthRules } from '@/api/index'
|
|
import FaIcon from '@/components/FaIcon.vue'
|
|
|
|
export default {
|
|
components: { FaIcon },
|
|
data() {
|
|
return {
|
|
themeConfig: getThemeConfigFromStorage() || THEME_PRESETS['default'],
|
|
pageData: {
|
|
title: '成长规则',
|
|
subtitle: '',
|
|
sections: []
|
|
},
|
|
currentCategory: 'all',
|
|
showAchievements: false,
|
|
expandedFaq: null
|
|
}
|
|
},
|
|
onLoad() {
|
|
const latestTheme = getThemeConfigFromStorage() || THEME_PRESETS['default']
|
|
if (JSON.stringify(latestTheme) !== JSON.stringify(this.themeConfig)) {
|
|
this.themeConfig = latestTheme
|
|
}
|
|
this.loadRules()
|
|
},
|
|
onShow() {
|
|
const latestTheme = getThemeConfigFromStorage() || THEME_PRESETS['default']
|
|
if (JSON.stringify(latestTheme) !== JSON.stringify(this.themeConfig)) {
|
|
this.themeConfig = latestTheme
|
|
}
|
|
refreshNavBarTheme()
|
|
setTimeout(() => {
|
|
forceApplyTabBarTheme(latestTheme)
|
|
}, 100)
|
|
},
|
|
methods: {
|
|
async loadRules() {
|
|
try {
|
|
const res = await getGrowthRules()
|
|
if (res) {
|
|
this.pageData = {
|
|
title: res.title || '成长规则',
|
|
subtitle: res.subtitle || '',
|
|
sections: res.sections || []
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log('加载规则失败:', e)
|
|
}
|
|
},
|
|
|
|
getSectionIcon(type) {
|
|
const iconMap = {
|
|
'level_system': 'arrow-up',
|
|
'exp_rules': 'wand-magic-sparkles',
|
|
'streak_bonus': 'fire',
|
|
'protection': 'shield-halved',
|
|
'achievement_system': 'medal',
|
|
'privileges': 'crown',
|
|
'tips': 'lightbulb',
|
|
'faq': 'circle-question'
|
|
}
|
|
return iconMap[type] || 'list'
|
|
},
|
|
|
|
getTipColor(index) {
|
|
const colors = ['#4cb8c6', '#667eea', '#764ba2', '#ff9f43', '#10b981', '#f59e0b']
|
|
return colors[index % colors.length]
|
|
},
|
|
|
|
getExpRuleBg(index) {
|
|
const colors = [
|
|
'linear-gradient(135deg, #667eea20 0%, #764ba215 100%)',
|
|
'linear-gradient(135deg, #f59e0b20 0%, #d9770615 100%)',
|
|
'linear-gradient(135deg, #ec489920 0%, #be185d15 100%)'
|
|
]
|
|
return colors[index % colors.length]
|
|
},
|
|
|
|
getExpRuleIcon(index) {
|
|
const icons = ['book-open', 'money-bill', 'face-smile']
|
|
return icons[index % icons.length]
|
|
},
|
|
|
|
getCategoryColor(category) {
|
|
const colors = {
|
|
'streak': 'linear-gradient(135deg, #F59E0B 0%, #D97706 100%)',
|
|
'task': 'linear-gradient(135deg, #9B8AFB 0%, #7B6CEB 100%)',
|
|
'mood': 'linear-gradient(135deg, #EC4899 0%, #BE185D 100%)',
|
|
'bill': 'linear-gradient(135deg, #4ECDC4 0%, #3BA9A1 100%)',
|
|
'review': 'linear-gradient(135deg, #7B6CEB 0%, #5A4BD1 100%)'
|
|
}
|
|
return colors[category] || colors['task']
|
|
},
|
|
|
|
getCategoryBg(category) {
|
|
const colors = {
|
|
'streak': 'rgba(245, 158, 11, 0.15)',
|
|
'task': 'rgba(155, 138, 251, 0.15)',
|
|
'mood': 'rgba(236, 72, 153, 0.15)',
|
|
'bill': 'rgba(78, 205, 196, 0.15)',
|
|
'review': 'rgba(123, 108, 235, 0.15)'
|
|
}
|
|
return colors[category] || colors['task']
|
|
},
|
|
|
|
getCategoryName(category) {
|
|
const names = {
|
|
'streak': '坚持',
|
|
'task': '任务',
|
|
'mood': '心情',
|
|
'bill': '账单',
|
|
'review': '复盘'
|
|
}
|
|
return names[category] || '其他'
|
|
},
|
|
|
|
getFilteredAchievements(section) {
|
|
const list = section.achievements || section.data || []
|
|
if (this.currentCategory === 'all') {
|
|
return list
|
|
}
|
|
return list.filter(item => item.category === this.currentCategory)
|
|
},
|
|
|
|
getCategoryIcon(category) {
|
|
// 兼容旧调用:返回 emoji 字符替代 FaIcon
|
|
return this.getCategoryEmoji(category)
|
|
},
|
|
|
|
getCategoryEmoji(category) {
|
|
const emojis = {
|
|
'all': '🏆',
|
|
'streak': '🔥',
|
|
'task': '📋',
|
|
'mood': '🌈',
|
|
'bill': '💰',
|
|
'review': '✨'
|
|
}
|
|
return emojis[category] || '🏆'
|
|
},
|
|
|
|
getCatName(category) {
|
|
const names = {
|
|
'all': '全部',
|
|
'streak': '坚持',
|
|
'task': '任务',
|
|
'mood': '心情',
|
|
'bill': '账单',
|
|
'review': '复盘'
|
|
}
|
|
return names[category] || '全部'
|
|
},
|
|
|
|
toggleAchievements() {
|
|
this.showAchievements = !this.showAchievements
|
|
},
|
|
|
|
toggleFaq(index) {
|
|
this.expandedFaq = this.expandedFaq === index ? null : index
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.rules-page {
|
|
min-height: 100vh;
|
|
padding: 20rpx 24rpx;
|
|
padding-bottom: 40px;
|
|
box-sizing: border-box;
|
|
position: relative;
|
|
}
|
|
|
|
.theme-transition {
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.rules-content {
|
|
height: 100vh;
|
|
}
|
|
|
|
.page-header {
|
|
padding: 60rpx 24rpx 48rpx;
|
|
text-align: center;
|
|
border-radius: 0 0 20rpx 20rpx;
|
|
margin-bottom: 20rpx;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.page-header::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: -50%;
|
|
left: -50%;
|
|
width: 200%;
|
|
height: 200%;
|
|
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 50%);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.page-title {
|
|
font-size: 42rpx;
|
|
font-weight: 700;
|
|
color: #fff;
|
|
display: block;
|
|
margin-bottom: 12rpx;
|
|
letter-spacing: 2rpx;
|
|
}
|
|
|
|
.page-subtitle {
|
|
font-size: 26rpx;
|
|
color: rgba(255, 255, 255, 0.85);
|
|
display: block;
|
|
}
|
|
|
|
|
|
.section-card {
|
|
border-radius: 14rpx;
|
|
padding: 24rpx;
|
|
margin-bottom: 20rpx;
|
|
box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12rpx;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.section-icon-wrap {
|
|
width: 56rpx;
|
|
height: 56rpx;
|
|
border-radius: 14rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.section-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 30rpx;
|
|
font-weight: 700;
|
|
color: #2c3e50;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.section-content {
|
|
padding: 12rpx 16rpx;
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 12rpx;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.content-text {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* 等级系统 */
|
|
.level-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.level-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
padding: 18rpx 20rpx;
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 14rpx;
|
|
transition: all 0.2s ease;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.level-item::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: -100%;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
|
transition: left 0.5s ease;
|
|
}
|
|
|
|
.level-item:active::before {
|
|
left: 100%;
|
|
}
|
|
|
|
.level-item:active {
|
|
transform: scale(0.99);
|
|
background: rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.level-badge-wrap {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 6rpx;
|
|
width: 90rpx;
|
|
}
|
|
|
|
.level-badge {
|
|
width: 64rpx;
|
|
height: 64rpx;
|
|
border-radius: 16rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.12);
|
|
position: relative;
|
|
}
|
|
|
|
.level-badge::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: -3rpx;
|
|
left: -3rpx;
|
|
right: -3rpx;
|
|
bottom: -3rpx;
|
|
border-radius: 18rpx;
|
|
background: linear-gradient(135deg, rgba(255,255,255,0.35), transparent);
|
|
}
|
|
|
|
.level-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.level-number {
|
|
font-size: 20rpx;
|
|
font-weight: 600;
|
|
color: #666;
|
|
}
|
|
|
|
.level-info {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.level-title {
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.level-progress {
|
|
width: 100%;
|
|
}
|
|
|
|
.progress-track {
|
|
height: 6rpx;
|
|
border-radius: 100rpx;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
border-radius: 100rpx;
|
|
transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
position: relative;
|
|
}
|
|
|
|
.progress-fill::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 50%;
|
|
background: linear-gradient(to bottom, rgba(255,255,255,0.25), transparent);
|
|
border-radius: 100rpx 100rpx 0 0;
|
|
}
|
|
|
|
.level-exp {
|
|
font-size: 28rpx;
|
|
font-weight: 700;
|
|
width: 120rpx;
|
|
text-align: right;
|
|
}
|
|
|
|
.level-privileges {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8rpx;
|
|
margin-top: 6rpx;
|
|
}
|
|
|
|
.privilege-item {
|
|
font-size: 20rpx;
|
|
padding: 4rpx 10rpx;
|
|
background: rgba(0, 0, 0, 0.05);
|
|
border-radius: 8rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.level-name {
|
|
display: block;
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
margin-bottom: 6rpx;
|
|
}
|
|
|
|
/* 经验规则 */
|
|
.exp-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.exp-limit {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12rpx;
|
|
padding: 14rpx 18rpx;
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.limit-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.limit-text {
|
|
font-size: 24rpx;
|
|
font-weight: 600;
|
|
color: #666;
|
|
}
|
|
|
|
.exp-rules-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12rpx;
|
|
}
|
|
|
|
.exp-rule-card {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 14rpx;
|
|
padding: 16rpx 18rpx;
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 14rpx;
|
|
}
|
|
|
|
.rule-icon-box {
|
|
width: 56rpx;
|
|
height: 56rpx;
|
|
border-radius: 14rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.rule-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.rule-content {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8rpx;
|
|
}
|
|
|
|
.rule-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.rule-title {
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.rule-exp {
|
|
font-size: 24rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.rule-detail {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.rule-info {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6rpx;
|
|
}
|
|
|
|
.rule-name {
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.rule-reward {
|
|
font-size: 24rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.rule-desc {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* 连续打卡加成 */
|
|
.streak-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14rpx;
|
|
}
|
|
|
|
.streak-formula {
|
|
padding: 14rpx 18rpx;
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.formula-text {
|
|
font-size: 24rpx;
|
|
font-weight: 600;
|
|
color: #666;
|
|
}
|
|
|
|
.streak-rules {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6rpx;
|
|
}
|
|
|
|
.streak-card {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 14rpx 18rpx;
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.streak-line {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12rpx;
|
|
}
|
|
|
|
.line-dot {
|
|
width: 10rpx;
|
|
height: 10rpx;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.streak-range {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.streak-bonus {
|
|
font-size: 24rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.streak-tip {
|
|
padding: 16rpx 20rpx;
|
|
background: rgba(255, 193, 7, 0.1);
|
|
border-radius: 12rpx;
|
|
border-left: 4rpx solid #ffc107;
|
|
}
|
|
|
|
.tip-text {
|
|
font-size: 22rpx;
|
|
color: #856404;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* 新手保护 */
|
|
.protection-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.protection-main {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
padding: 18rpx;
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 14rpx;
|
|
}
|
|
|
|
.main-title {
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.bonus-tag {
|
|
display: inline-flex;
|
|
padding: 6rpx 14rpx;
|
|
border-radius: 10rpx;
|
|
width: fit-content;
|
|
}
|
|
|
|
.tag-text {
|
|
font-size: 22rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.protection-detail {
|
|
padding: 14rpx 18rpx;
|
|
background: #fff;
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.detail-text {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.protection-example {
|
|
padding: 14rpx 18rpx;
|
|
background: rgba(255, 235, 59, 0.08);
|
|
border-radius: 12rpx;
|
|
border-left: 4rpx solid #ffc107;
|
|
}
|
|
|
|
.example-text {
|
|
font-size: 22rpx;
|
|
color: #856404;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.protection-name {
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.protection-desc {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.protection-highlight {
|
|
font-size: 24rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.protection-tip {
|
|
padding: 20rpx;
|
|
border-radius: 14rpx;
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* 成就系统 */
|
|
.achievement-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.achievement-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 16rpx 20rpx;
|
|
background: rgba(0, 0, 0, 0.03);
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.toggle-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12rpx;
|
|
}
|
|
|
|
.toggle-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.toggle-text {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.toggle-arrow {
|
|
font-size: 20rpx;
|
|
color: #999;
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.toggle-arrow.expanded {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.achievement-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14rpx;
|
|
}
|
|
|
|
.category-tabs {
|
|
display: flex;
|
|
gap: 8rpx;
|
|
}
|
|
|
|
.category-tab {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 6rpx;
|
|
padding: 12rpx 8rpx;
|
|
background: rgba(0, 0, 0, 0.03);
|
|
border-radius: 12rpx;
|
|
flex: 1;
|
|
transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
}
|
|
|
|
.category-tab:active {
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
.category-tab.active {
|
|
background: linear-gradient(135deg, rgba(155, 138, 251, 0.18) 0%, rgba(123, 108, 235, 0.12) 100%);
|
|
box-shadow: 0 4rpx 12rpx rgba(155, 138, 251, 0.18);
|
|
}
|
|
|
|
.tab-emoji {
|
|
font-size: 28rpx;
|
|
line-height: 1;
|
|
display: block;
|
|
transition: transform 0.2s ease;
|
|
}
|
|
|
|
.category-tab.active .tab-emoji {
|
|
transform: scale(1.15);
|
|
}
|
|
|
|
.tab-name {
|
|
font-size: 20rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.category-tab.active .tab-name {
|
|
color: #7B6CEB;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.achievement-desc {
|
|
padding: 16rpx 20rpx;
|
|
background: rgba(0, 0, 0, 0.03);
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.desc-text {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.rarity-info {
|
|
padding: 12rpx 20rpx;
|
|
background: rgba(255, 235, 59, 0.1);
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.rarity-text {
|
|
font-size: 22rpx;
|
|
color: #856404;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.achievement-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.achievement-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12rpx;
|
|
padding: 18rpx 16rpx;
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 16rpx;
|
|
transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.achievement-card:active {
|
|
transform: scale(0.96);
|
|
background: rgba(0, 0, 0, 0.04);
|
|
}
|
|
|
|
.achievement-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 6rpx;
|
|
height: 100%;
|
|
background: linear-gradient(180deg, #9B8AFB 0%, #7B6CEB 100%);
|
|
}
|
|
|
|
.achievement-card.legendary::before {
|
|
background: linear-gradient(180deg, #FFD700 0%, #FFA500 50%, #FFD700 100%);
|
|
}
|
|
|
|
.achievement-card.epic::before {
|
|
background: linear-gradient(180deg, #A330C9 0%, #7B2CBF 50%, #A330C9 100%);
|
|
}
|
|
|
|
.achievement-card.rare::before {
|
|
background: linear-gradient(180deg, #3B82F6 0%, #1D4ED8 50%, #3B82F6 100%);
|
|
}
|
|
|
|
.card-icon-wrap {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
align-self: center;
|
|
}
|
|
|
|
.card-icon {
|
|
width: 76rpx;
|
|
height: 76rpx;
|
|
border-radius: 20rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.12);
|
|
}
|
|
|
|
.card-icon::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -50%;
|
|
left: -50%;
|
|
width: 200%;
|
|
height: 200%;
|
|
background: radial-gradient(circle, rgba(255, 255, 255, 0.18) 0%, transparent 60%);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.card-emoji {
|
|
font-size: 44rpx;
|
|
line-height: 1;
|
|
display: block;
|
|
filter: drop-shadow(0 2rpx 4rpx rgba(0, 0, 0, 0.15));
|
|
}
|
|
|
|
.card-rarity-flag {
|
|
position: absolute;
|
|
top: -8rpx;
|
|
right: -14rpx;
|
|
padding: 2rpx 10rpx;
|
|
border-radius: 100rpx;
|
|
font-size: 18rpx;
|
|
font-weight: 700;
|
|
background: #999;
|
|
color: #fff;
|
|
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.card-rarity-flag text {
|
|
color: #fff;
|
|
}
|
|
|
|
.rarity-flag.legendary {
|
|
background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
|
|
}
|
|
|
|
.rarity-flag.epic {
|
|
background: linear-gradient(135deg, #A330C9 0%, #7B2CBF 100%);
|
|
}
|
|
|
|
.rarity-flag.rare {
|
|
background: linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%);
|
|
}
|
|
|
|
.card-desc {
|
|
font-size: 22rpx;
|
|
color: #333;
|
|
text-align: center;
|
|
line-height: 1.5;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.card-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 6rpx;
|
|
}
|
|
|
|
.cat-tag {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6rpx;
|
|
font-size: 19rpx;
|
|
padding: 4rpx 12rpx;
|
|
border-radius: 100rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.cat-tag-text {
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.rarity-dot {
|
|
width: 8rpx;
|
|
height: 8rpx;
|
|
border-radius: 50%;
|
|
background: #999;
|
|
}
|
|
|
|
.rarity-dot.legendary {
|
|
background: #FFD700;
|
|
box-shadow: 0 0 8rpx #FFD700;
|
|
}
|
|
|
|
.rarity-dot.epic {
|
|
background: #A330C9;
|
|
box-shadow: 0 0 8rpx #A330C9;
|
|
}
|
|
|
|
.rarity-dot.rare {
|
|
background: #3B82F6;
|
|
box-shadow: 0 0 8rpx #3B82F6;
|
|
}
|
|
|
|
.exp-text {
|
|
font-size: 22rpx;
|
|
font-weight: 600;
|
|
color: #666;
|
|
}
|
|
|
|
|
|
|
|
/* 特权列表 */
|
|
.privileges-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.privilege-card {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14rpx;
|
|
padding: 16rpx 18rpx;
|
|
background: rgba(16, 185, 129, 0.06);
|
|
border-radius: 14rpx;
|
|
}
|
|
|
|
.privilege-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.privilege-info {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4rpx;
|
|
}
|
|
|
|
.privilege-name {
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.privilege-desc {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
}
|
|
|
|
/* 技巧提示 */
|
|
.tips-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.tip-card {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14rpx;
|
|
padding: 14rpx 18rpx;
|
|
background: rgba(255, 235, 59, 0.08);
|
|
border-radius: 12rpx;
|
|
border-left: 4rpx solid #ffc107;
|
|
}
|
|
|
|
.tip-icon-wrap {
|
|
width: 50rpx;
|
|
height: 50rpx;
|
|
border-radius: 12rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.tip-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.tip-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.tip-text {
|
|
font-size: 24rpx;
|
|
line-height: 1.6;
|
|
color: #666;
|
|
}
|
|
|
|
.tip-reward {
|
|
font-size: 22rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* FAQ问答 */
|
|
.faq-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.faq-card {
|
|
background: rgba(0, 0, 0, 0.025);
|
|
border-radius: 14rpx;
|
|
overflow: hidden;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.faq-card:active {
|
|
transform: scale(0.995);
|
|
background: rgba(0, 0, 0, 0.04);
|
|
}
|
|
|
|
.faq-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 18rpx;
|
|
}
|
|
|
|
.faq-q {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 12rpx;
|
|
flex: 1;
|
|
}
|
|
|
|
.faq-q-icon {
|
|
margin-top: 2rpx;
|
|
transition: transform 0.2s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.faq-q-text {
|
|
font-size: 26rpx;
|
|
font-weight: 600;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.faq-arrow {
|
|
font-size: 18rpx;
|
|
color: #999;
|
|
transition: transform 0.3s ease;
|
|
margin-left: 12rpx;
|
|
}
|
|
|
|
.faq-arrow.expanded {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.faq-a {
|
|
max-height: 0;
|
|
overflow: hidden;
|
|
transition: max-height 0.3s ease, padding 0.3s ease, opacity 0.2s ease;
|
|
opacity: 0;
|
|
}
|
|
|
|
.faq-a.expanded {
|
|
max-height: 500rpx;
|
|
padding: 0 18rpx 18rpx 58rpx;
|
|
opacity: 1;
|
|
}
|
|
|
|
.answer-content {
|
|
background: rgba(255, 255, 255, 0.8);
|
|
border-radius: 12rpx;
|
|
padding: 16rpx;
|
|
}
|
|
|
|
.faq-a-text {
|
|
flex: 1;
|
|
font-size: 24rpx;
|
|
line-height: 1.6;
|
|
color: #666;
|
|
}
|
|
|
|
.safe-area-bottom {
|
|
height: env(safe-area-inset-bottom);
|
|
}
|
|
</style> |