Files
text-adventure-game/components/panels/LogPanel.vue

193 lines
3.5 KiB
Vue
Raw Normal View History

<template>
<scroll-view
class="log-panel"
scroll-y
:scroll-into-view="scrollToId"
:scroll-with-animation="true"
:scroll-top="scrollTop"
>
<view
v-for="log in logs"
:key="log.id"
class="log-item"
:class="`log-item--${log.type}`"
:id="'log-' + log.id"
>
<text class="log-item__icon">{{ getLogIcon(log.type) }}</text>
<text class="log-item__time">[{{ log.time }}]</text>
<text class="log-item__message">{{ log.message }}</text>
</view>
<view :id="'log-anchor-' + lastLogId" class="log-anchor"></view>
</scroll-view>
</template>
<script setup>
import { computed, watch, nextTick, ref } from 'vue'
import { useGameStore } from '@/store/game'
const game = useGameStore()
const scrollToId = ref('')
const scrollTop = ref(0)
const logs = computed(() => game.logs)
const lastLogId = computed(() => {
return logs.value.length > 0 ? logs.value[logs.value.length - 1].id : 0
})
watch(lastLogId, (newId) => {
if (newId) {
nextTick(() => {
scrollToId.value = 'log-anchor-' + newId
// 重置scrollToId以允许下次滚动
setTimeout(() => {
scrollToId.value = ''
}, 100)
})
}
}, { immediate: true })
// 获取日志类型图标
function getLogIcon(type) {
const icons = {
combat: '⚔️',
system: '🔔',
reward: '🎁',
info: '',
warning: '⚠️',
error: '❌',
success: '✅',
story: '📖'
}
return icons[type] || '•'
}
</script>
<style lang="scss" scoped>
.log-panel {
height: 100%;
padding: 12rpx 16rpx;
background-color: $bg-primary;
}
.log-item {
display: flex;
align-items: flex-start;
padding: 8rpx 12rpx;
margin-bottom: 4rpx;
border-radius: 6rpx;
background-color: $bg-secondary;
border-left: 3rpx solid transparent;
animation: slideIn 0.2s ease;
&__icon {
font-size: 20rpx;
margin-right: 8rpx;
flex-shrink: 0;
}
&__time {
color: $text-muted;
font-size: 20rpx;
margin-right: 8rpx;
flex-shrink: 0;
}
&__message {
color: $text-primary;
font-size: 24rpx;
line-height: 1.5;
flex: 1;
word-break: break-word;
}
// 不同类型的日志样式
&--combat {
background-color: rgba($danger, 0.1);
border-left-color: $danger;
.log-item__message {
color: $danger;
}
}
&--system {
background-color: rgba($accent, 0.1);
border-left-color: $accent;
.log-item__message {
color: $accent;
font-weight: 500;
}
}
&--reward {
background-color: rgba($warning, 0.1);
border-left-color: $warning;
.log-item__message {
color: $warning;
font-weight: 500;
}
}
&--info {
.log-item__message {
color: $text-secondary;
}
}
&--warning {
background-color: rgba($warning, 0.1);
border-left-color: $warning;
.log-item__message {
color: $warning;
}
}
&--error {
background-color: rgba($danger, 0.15);
border-left-color: $danger;
.log-item__message {
color: $danger;
}
}
&--success {
background-color: rgba($success, 0.1);
border-left-color: $success;
.log-item__message {
color: $success;
}
}
&--story {
background-color: rgba($info, 0.1);
border-left-color: $info;
.log-item__message {
color: $info;
font-style: italic;
}
}
}
.log-anchor {
height: 1rpx;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20rpx);
}
to {
opacity: 1;
transform: translateX(0);
}
}
</style>