pet_data/app/components/pixel/DeityPanel.vue

216 lines
8.0 KiB
Vue
Raw Normal View History

2025-11-27 08:42:55 +00:00
<template>
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm" @click.self="$emit('close')">
<div class="relative w-full max-w-md bg-[#1b1026] border-4 border-[#4a3b5e] shadow-2xl p-4 m-4 max-h-[90vh] overflow-y-auto custom-scrollbar">
<!-- Close Button -->
<button
@click="$emit('close')"
class="absolute top-2 right-2 text-[#8f80a0] hover:text-white"
>
<X :size="24" />
</button>
<!-- Header -->
<div class="text-center mb-6">
<h2 class="text-2xl font-bold text-[#f6b26b] font-mono tracking-wider">守護神明</h2>
<div class="h-1 w-24 bg-[#f6b26b] mx-auto mt-2"></div>
</div>
<div v-if="currentDeity && currentStage" class="flex flex-col gap-6">
<!-- Deity Portrait & Info -->
<div class="flex flex-col items-center">
<div class="w-32 h-32 bg-[#0f0816] border-4 border-[#f6b26b] rounded-full flex items-center justify-center mb-4 relative overflow-hidden group">
<!-- Glow Effect -->
<div class="absolute inset-0 bg-[#f6b26b] opacity-10 animate-pulse"></div>
<!-- Icon Placeholder (Replace with actual image later) -->
<div class="text-6xl">{{ getDeityIcon(String(currentDeity.id)) }}</div>
<!-- Stage Badge -->
<div class="absolute bottom-0 bg-[#f6b26b] text-[#1b1026] text-xs font-bold px-3 py-1 rounded-full border-2 border-[#1b1026]">
Lv.{{ currentStage.level }}
</div>
</div>
<h3 class="text-xl font-bold text-[#e0d8f0]">{{ currentStage.name }}</h3>
<p class="text-[#f6b26b] text-sm font-mono mb-2">{{ currentStage.title }}</p>
<p class="text-[#8f80a0] text-xs text-center max-w-[80%]">{{ currentStage.description }}</p>
</div>
<!-- Evolution Progress -->
<div class="bg-[#0f0816] p-4 border-2 border-[#4a3b5e] rounded-lg">
<div class="flex justify-between items-center mb-2">
<span class="text-[#e0d8f0] text-sm font-bold">進化進度</span>
<span class="text-[#8f80a0] text-xs">{{ currentDeityState.exp }} / {{ nextStageExp }} EXP</span>
</div>
<div class="w-full h-4 bg-[#2b193f] rounded-full overflow-hidden border border-[#4a3b5e]">
<div
class="h-full bg-gradient-to-r from-[#f6b26b] to-[#d95763] transition-all duration-500"
:style="{ width: `${expPercentage}%` }"
></div>
</div>
<!-- Evolve Button -->
<button
v-if="canEvolve"
@click="$emit('evolve')"
class="w-full mt-4 py-2 bg-[#f6b26b] text-[#1b1026] font-bold rounded hover:bg-[#ffe762] transition-colors animate-pulse"
>
立即進化
</button>
</div>
<!-- Active Buffs -->
<div class="bg-[#0f0816] p-4 border-2 border-[#4a3b5e] rounded-lg">
<h4 class="text-[#2ce8f4] text-sm font-bold mb-3 border-b border-[#2ce8f4]/30 pb-1">神力加成</h4>
<div class="grid grid-cols-2 gap-2">
<div v-for="(value, key) in currentStage.buffs" :key="key" class="flex items-center gap-2 text-xs text-[#e0d8f0]">
<span class="w-1.5 h-1.5 bg-[#2ce8f4] rounded-full"></span>
{{ formatBuff(key, value) }}
</div>
</div>
</div>
<!-- Quests -->
<div class="bg-[#0f0816] p-4 border-2 border-[#4a3b5e] rounded-lg">
<h4 class="text-[#99e550] text-sm font-bold mb-3 border-b border-[#99e550]/30 pb-1">進化任務</h4>
<div class="space-y-3">
<div v-for="quest in currentDeity.quests" :key="quest.id" class="relative">
<div class="flex justify-between items-start mb-1">
<span class="text-[#e0d8f0] text-xs">{{ quest.description }}</span>
<span class="text-[#99e550] text-xs font-mono">
{{ getQuestProgress(quest.id) }} / {{ quest.target }}
</span>
</div>
<div class="w-full h-1.5 bg-[#2b193f] rounded-full overflow-hidden">
<div
class="h-full bg-[#99e550]"
:style="{ width: `${Math.min(100, (getQuestProgress(quest.id) / quest.target) * 100)}%` }"
></div>
</div>
</div>
</div>
</div>
<!-- Actions -->
<div class="grid grid-cols-2 gap-4">
<button
@click="$emit('divination')"
class="py-3 bg-[#2b193f] border-2 border-[#2ce8f4] text-[#2ce8f4] font-bold rounded hover:bg-[#3d2459] transition-colors flex items-center justify-center gap-2"
>
<Sparkles :size="18" />
{{ currentDeity.origin === 'western' ? '塔羅占卜' : '每日求籤' }}
</button>
<button
@click="$emit('switch')"
class="py-3 bg-[#2b193f] border-2 border-[#8f80a0] text-[#8f80a0] font-bold rounded hover:bg-[#3d2459] transition-colors flex items-center justify-center gap-2"
>
<RefreshCw :size="18" />
更換神明
</button>
</div>
</div>
<!-- Empty State -->
<div v-else class="text-center py-12 text-[#8f80a0]">
<p>尚未供奉任何神明</p>
<button
@click="$emit('encounter')"
class="mt-4 px-6 py-2 bg-[#f6b26b] text-[#1b1026] font-bold rounded hover:bg-[#ffe762]"
>
尋找緣分
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { X, Sparkles, RefreshCw } from 'lucide-vue-next';
const props = defineProps<{
currentDeity: any;
currentDeityState: any;
currentStage: any;
}>();
defineEmits(['close', 'evolve', 'divination', 'switch', 'encounter']);
const nextStageExp = computed(() => {
if (!props.currentDeity || !props.currentStage) return 100;
const nextStage = props.currentDeity.stages.find((s: any) => s.level === props.currentStage.level + 1);
return nextStage ? nextStage.requiredExp : props.currentStage.requiredExp;
});
const expPercentage = computed(() => {
if (!props.currentDeityState) return 0;
return Math.min(100, (props.currentDeityState.exp / nextStageExp.value) * 100);
});
const canEvolve = computed(() => {
if (!props.currentDeity || !props.currentDeityState) return false;
// Check max level
if (props.currentStage.level >= props.currentDeity.stages.length) return false;
// Check EXP
if (props.currentDeityState.exp < nextStageExp.value) return false;
// Check Quests
return props.currentDeity.quests.every((q: any) => {
return (props.currentDeityState.quests[q.id] || 0) >= q.target;
});
});
function getQuestProgress(questId: string) {
return props.currentDeityState?.quests?.[questId] || 0;
}
function formatBuff(key: string, value: any) {
const map: Record<string, string> = {
gameSuccessRate: '遊戲成功率',
sicknessReduction: '生病機率',
happinessRecovery: '快樂恢復',
dropRate: '掉寶率',
resourceGain: '資源獲得',
intGain: '智力成長',
miniGameBonus: '小遊戲獎勵',
healthRecovery: '健康恢復',
badEventReduction: '壞事機率',
defense: '防禦力',
attack: '攻擊力',
luck: '運氣',
str: '力量',
int: '智力',
dex: '敏捷',
health: '最大健康',
sicknessImmune: '免疫生病'
};
const label = map[key] || key;
if (key === 'sicknessImmune') return label;
const isPercent = typeof value === 'number' && value < 1 && value > -1;
const valStr = isPercent ? `${Math.round(value * 100)}%` : value;
const prefix = value > 0 ? '+' : '';
return `${label} ${prefix}${valStr}`;
}
function getDeityIcon(id: string) {
const icons: Record<string, string> = {
mazu: '🌊',
earthgod: '🏮',
yuelao: '❤️',
wenchang: '📜',
guanyin: '🪷',
athena: '🦉'
};
return icons[id] || '✨';
}
</script>