You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
445 lines
9.9 KiB
445 lines
9.9 KiB
|
2 months ago
|
<script setup lang="ts">
|
||
|
|
import { computed, ref } from 'vue'
|
||
|
|
import { useAuthStore } from '@/stores/auth'
|
||
|
|
import { useCharacterStore } from '@/stores/character'
|
||
|
|
import { useRouter } from 'vue-router'
|
||
|
|
import Particles from '@/components/Particles/Particles.vue'
|
||
|
|
import GlareHover from '@/components/GlareHover/GlareHover.vue'
|
||
|
|
import ChatBox from '@/components/ChatBox.vue'
|
||
|
|
|
||
|
|
const authStore = useAuthStore()
|
||
|
|
const characterStore = useCharacterStore()
|
||
|
|
const router = useRouter()
|
||
|
|
|
||
|
|
const isTraining = computed(() => !!characterStore.currentCharacter?.trainingOn)
|
||
|
|
|
||
|
|
const canBreakthrough = computed(() => characterStore.currentCharacter?.canBreakthrough ?? false)
|
||
|
|
const currentLevelName = computed(() => characterStore.currentCharacter?.levelName ?? '')
|
||
|
|
const currentExp = computed(() => characterStore.currentCharacter?.currentExp ?? 0)
|
||
|
|
const nextLevelName = computed(() => characterStore.currentCharacter?.nextLevelName ?? '')
|
||
|
|
const nextLevelMinExp = computed(() => characterStore.currentCharacter?.nextLevelMinExp ?? 0)
|
||
|
|
const breakthroughRate = computed(() => characterStore.currentCharacter?.breakthroughRate ?? 0)
|
||
|
|
|
||
|
|
const expProgress = computed(() => {
|
||
|
|
if (!nextLevelMinExp.value) return 0
|
||
|
|
return Math.min(100, (currentExp.value / nextLevelMinExp.value) * 100)
|
||
|
|
})
|
||
|
|
|
||
|
|
const breakthroughMessage = ref('')
|
||
|
|
const showBreakthroughMessage = ref(false)
|
||
|
|
|
||
|
|
const menuItems = computed(() => [
|
||
|
|
{ label: '任务', icon: '🗺️' },
|
||
|
|
{ label: '战斗', icon: '⚔️' },
|
||
|
|
{ label: '背包', icon: '🎒' },
|
||
|
|
{ label: '角色', icon: '👤' },
|
||
|
|
{ label: isTraining.value ? '打坐中' : '打坐', icon: isTraining.value ? '🔥' : '🧘', isTraining: isTraining.value },
|
||
|
|
])
|
||
|
|
|
||
|
|
const handleLogout = () => {
|
||
|
|
authStore.logout()
|
||
|
|
characterStore.clearCurrentCharacter()
|
||
|
|
window.location.href = '/login'
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleSwitchCharacter = () => {
|
||
|
|
window.location.href = '/character'
|
||
|
|
}
|
||
|
|
|
||
|
|
const navigateTo = (item: { label: string }) => {
|
||
|
|
if (item.label === '打坐' || item.label === '打坐中') {
|
||
|
|
router.push('/training')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleBreakthrough = async () => {
|
||
|
|
const result = await characterStore.breakthrough()
|
||
|
|
breakthroughMessage.value = result.message
|
||
|
|
showBreakthroughMessage.value = true
|
||
|
|
setTimeout(() => {
|
||
|
|
showBreakthroughMessage.value = false
|
||
|
|
}, 3000)
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<template>
|
||
|
|
<div class="game-page">
|
||
|
|
<Particles
|
||
|
|
:particle-count="100"
|
||
|
|
:particle-colors="['#ffffff', '#cccccc']"
|
||
|
|
class="particles-bg"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<div class="game-container">
|
||
|
|
<div class="character-header" @click="handleSwitchCharacter">
|
||
|
|
<div class="character-info">
|
||
|
|
<span class="character-name">{{ characterStore.currentCharacter?.name || '未选择角色' }}</span>
|
||
|
|
<span class="character-level">{{ characterStore.currentCharacter?.levelName || '' }}</span>
|
||
|
|
</div>
|
||
|
|
<span class="switch-btn">切换角色</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h1 class="welcome-text">欢迎来到CUPOWER</h1>
|
||
|
|
|
||
|
|
<div class="menu-grid">
|
||
|
|
<GlareHover
|
||
|
|
v-for="item in menuItems"
|
||
|
|
:key="item.label"
|
||
|
|
width="100%"
|
||
|
|
height="120px"
|
||
|
|
:background="item.isTraining ? 'rgba(255,136,68,0.1)' : 'rgba(255,255,255,0.02)'"
|
||
|
|
border-radius="16px"
|
||
|
|
:border-color="item.isTraining ? 'rgba(255,136,68,0.3)' : 'rgba(255,255,255,0.08)'"
|
||
|
|
:glare-color="item.isTraining ? '#ff8844' : '#ffffff'"
|
||
|
|
:glare-opacity="0.1"
|
||
|
|
class="menu-card"
|
||
|
|
:class="{ 'training-active': item.isTraining }"
|
||
|
|
@click="navigateTo(item)"
|
||
|
|
>
|
||
|
|
<div class="menu-content">
|
||
|
|
<span class="menu-icon">{{ item.icon }}</span>
|
||
|
|
<span class="menu-label">{{ item.label }}</span>
|
||
|
|
</div>
|
||
|
|
</GlareHover>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div v-if="nextLevelName" class="breakthrough-section">
|
||
|
|
<div class="breakthrough-header">
|
||
|
|
<span class="breakthrough-title">境界突破</span>
|
||
|
|
</div>
|
||
|
|
<div class="breakthrough-info">
|
||
|
|
<div class="level-info">
|
||
|
|
<span class="current-level">{{ currentLevelName }}</span>
|
||
|
|
<span class="arrow">→</span>
|
||
|
|
<span class="next-level">{{ nextLevelName }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="exp-info">
|
||
|
|
<span class="exp-text">{{ currentExp }} / {{ nextLevelMinExp }} 经验</span>
|
||
|
|
<div class="exp-bar">
|
||
|
|
<div class="exp-fill" :style="{ width: expProgress + '%' }"></div>
|
||
|
|
</div>
|
||
|
|
<span class="exp-percent">{{ Math.floor(expProgress) }}%</span>
|
||
|
|
</div>
|
||
|
|
<div class="rate-info">
|
||
|
|
<span class="rate-label">突破成功率</span>
|
||
|
|
<span class="rate-value">{{ breakthroughRate }}%</span>
|
||
|
|
</div>
|
||
|
|
<button
|
||
|
|
class="breakthrough-btn"
|
||
|
|
:class="{ 'can-breakthrough': canBreakthrough }"
|
||
|
|
:disabled="!canBreakthrough"
|
||
|
|
@click="handleBreakthrough"
|
||
|
|
>
|
||
|
|
{{ canBreakthrough ? '突破' : '未满足突破条件' }}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div v-if="showBreakthroughMessage" class="toast-message">
|
||
|
|
{{ breakthroughMessage }}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<GlareHover
|
||
|
|
width="200px"
|
||
|
|
height="44px"
|
||
|
|
background="transparent"
|
||
|
|
border-radius="22px"
|
||
|
|
border-color="rgba(255,255,255,0.1)"
|
||
|
|
glare-color="#ffffff"
|
||
|
|
:glare-opacity="0.1"
|
||
|
|
class="logout-button"
|
||
|
|
@click="handleLogout"
|
||
|
|
>
|
||
|
|
<span class="logout-text">退出登录</span>
|
||
|
|
</GlareHover>
|
||
|
|
|
||
|
|
<ChatBox />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.game-page {
|
||
|
|
min-height: 100vh;
|
||
|
|
background: #000000;
|
||
|
|
padding: 20px;
|
||
|
|
padding-bottom: 60px;
|
||
|
|
position: relative;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.particles-bg {
|
||
|
|
position: fixed !important;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
width: 100% !important;
|
||
|
|
height: 100% !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
.game-container {
|
||
|
|
max-width: 480px;
|
||
|
|
margin: 0 auto;
|
||
|
|
padding-top: 20px;
|
||
|
|
position: relative;
|
||
|
|
z-index: 10;
|
||
|
|
}
|
||
|
|
|
||
|
|
.character-header {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
background: rgba(255, 255, 255, 0.03);
|
||
|
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
|
|
border-radius: 12px;
|
||
|
|
padding: 12px 16px;
|
||
|
|
margin-bottom: 20px;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.2s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.character-header:hover {
|
||
|
|
background: rgba(255, 255, 255, 0.05);
|
||
|
|
}
|
||
|
|
|
||
|
|
.character-info {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.character-name {
|
||
|
|
color: #ffffff;
|
||
|
|
font-size: 1rem;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.character-level {
|
||
|
|
color: #888888;
|
||
|
|
font-size: 0.8rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.switch-btn {
|
||
|
|
color: #666666;
|
||
|
|
font-size: 0.75rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.welcome-text {
|
||
|
|
font-size: 1.5rem;
|
||
|
|
font-weight: 300;
|
||
|
|
text-align: center;
|
||
|
|
color: #ffffff;
|
||
|
|
letter-spacing: 0.1em;
|
||
|
|
margin-bottom: 24px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.menu-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(3, 1fr);
|
||
|
|
gap: 16px;
|
||
|
|
margin-bottom: 32px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.menu-card {
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
.menu-card.training-active .menu-label {
|
||
|
|
color: #ff8844;
|
||
|
|
}
|
||
|
|
|
||
|
|
.menu-content {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.menu-icon {
|
||
|
|
font-size: 1.75rem;
|
||
|
|
opacity: 0.8;
|
||
|
|
}
|
||
|
|
|
||
|
|
.menu-label {
|
||
|
|
color: #cccccc;
|
||
|
|
font-size: 0.875rem;
|
||
|
|
font-weight: 400;
|
||
|
|
letter-spacing: 0.1em;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-section {
|
||
|
|
background: rgba(255, 255, 255, 0.03);
|
||
|
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
|
|
border-radius: 16px;
|
||
|
|
padding: 20px;
|
||
|
|
margin-bottom: 24px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-header {
|
||
|
|
display: flex;
|
||
|
|
justify-content: center;
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-title {
|
||
|
|
color: #ff8844;
|
||
|
|
font-size: 1rem;
|
||
|
|
font-weight: 500;
|
||
|
|
letter-spacing: 0.1em;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-info {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-info {
|
||
|
|
display: flex;
|
||
|
|
justify-content: center;
|
||
|
|
align-items: center;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.current-level {
|
||
|
|
color: #888888;
|
||
|
|
font-size: 0.9rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.arrow {
|
||
|
|
color: #555555;
|
||
|
|
font-size: 0.9rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.next-level {
|
||
|
|
color: #ffffff;
|
||
|
|
font-size: 0.9rem;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.exp-info {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 6px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.exp-text {
|
||
|
|
color: #666666;
|
||
|
|
font-size: 0.8rem;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.exp-bar {
|
||
|
|
height: 8px;
|
||
|
|
background: rgba(255, 255, 255, 0.1);
|
||
|
|
border-radius: 4px;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.exp-fill {
|
||
|
|
height: 100%;
|
||
|
|
background: linear-gradient(90deg, #ff8844, #ff6644);
|
||
|
|
border-radius: 4px;
|
||
|
|
transition: width 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.exp-percent {
|
||
|
|
color: #888888;
|
||
|
|
font-size: 0.75rem;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.rate-info {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
padding: 8px 12px;
|
||
|
|
background: rgba(255, 255, 255, 0.02);
|
||
|
|
border-radius: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.rate-label {
|
||
|
|
color: #666666;
|
||
|
|
font-size: 0.85rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.rate-value {
|
||
|
|
color: #ff8844;
|
||
|
|
font-size: 0.9rem;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-btn {
|
||
|
|
width: 100%;
|
||
|
|
padding: 14px;
|
||
|
|
border-radius: 10px;
|
||
|
|
font-size: 0.95rem;
|
||
|
|
font-weight: 500;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
border: none;
|
||
|
|
background: rgba(255, 255, 255, 0.05);
|
||
|
|
color: #555555;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-btn:disabled {
|
||
|
|
cursor: not-allowed;
|
||
|
|
opacity: 0.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-btn.can-breakthrough {
|
||
|
|
background: linear-gradient(135deg, #ff8844 0%, #ff6644 100%);
|
||
|
|
color: #ffffff;
|
||
|
|
}
|
||
|
|
|
||
|
|
.breakthrough-btn.can-breakthrough:hover {
|
||
|
|
transform: scale(1.02);
|
||
|
|
box-shadow: 0 4px 20px rgba(255, 136, 68, 0.4);
|
||
|
|
}
|
||
|
|
|
||
|
|
.toast-message {
|
||
|
|
position: fixed;
|
||
|
|
top: 80px;
|
||
|
|
left: 50%;
|
||
|
|
transform: translateX(-50%);
|
||
|
|
background: rgba(255, 255, 255, 0.9);
|
||
|
|
color: #000000;
|
||
|
|
padding: 12px 24px;
|
||
|
|
border-radius: 8px;
|
||
|
|
font-size: 0.9rem;
|
||
|
|
z-index: 1000;
|
||
|
|
animation: fadeIn 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes fadeIn {
|
||
|
|
from {
|
||
|
|
opacity: 0;
|
||
|
|
transform: translateX(-50%) translateY(-10px);
|
||
|
|
}
|
||
|
|
to {
|
||
|
|
opacity: 1;
|
||
|
|
transform: translateX(-50%) translateY(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.logout-button {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
margin: 0 auto;
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
.logout-text {
|
||
|
|
color: #888888;
|
||
|
|
font-size: 0.8rem;
|
||
|
|
font-weight: 400;
|
||
|
|
letter-spacing: 0.1em;
|
||
|
|
transition: color 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.logout-button:hover .logout-text {
|
||
|
|
color: #ffffff;
|
||
|
|
}
|
||
|
|
</style>
|