feat: 重构战报弹窗与模拟器视图,优化UI与逻辑

重构BattleReportDialog和BattleSimulatorView相关静态资源,替换旧版JS/CSS文件,提升界面一致性和交互体验。新增和优化空状态、滚动区域等通用UI组件,移除部分冗余composable,完善多语言内容。引入导弹逻辑,补充版本检测工具,提升整体代码结构和可维护性。
This commit is contained in:
谦君
2025-12-15 20:04:40 +08:00
parent 9b9fda0400
commit 59dd7bfd05
126 changed files with 3944 additions and 1487 deletions

View File

@@ -59,6 +59,22 @@
<CardDescription>{{ t('settings.gameSettingsDesc') }}</CardDescription>
</CardHeader>
<CardContent class="space-y-4">
<!-- 游戏倍率 -->
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between p-4 border rounded-lg gap-3">
<div class="space-y-1 flex-1">
<h3 class="font-medium">{{ t('settings.gameSpeed') }}</h3>
<p class="text-sm text-muted-foreground">{{ t('settings.gameSpeedDesc') }}</p>
</div>
<div class="flex items-center gap-2 sm:gap-4 w-full sm:w-auto">
<div class="flex items-center gap-2 flex-1 sm:flex-initial">
<Button @click="decreaseSpeed" variant="outline" size="sm" :disabled="gameStore.gameSpeed <= 0.5">-</Button>
<span class="min-w-[60px] text-center font-medium">{{ gameStore.gameSpeed || 1 }}x</span>
<Button @click="increaseSpeed" variant="outline" size="sm" :disabled="gameStore.gameSpeed >= 10">+</Button>
</div>
<Button @click="resetSpeed" variant="ghost" size="sm">{{ t('settings.reset') }}</Button>
</div>
</div>
<!-- 游戏暂停 -->
<div class="flex items-center justify-between p-4 border rounded-lg">
<div class="space-y-1">
@@ -88,6 +104,15 @@
<span class="text-muted-foreground">{{ t('settings.buildDate') }}:</span>
<span class="font-medium">{{ pkg.buildDate }}</span>
</div>
<!-- 检查更新按钮 -->
<div class="pt-2">
<Button @click="handleCheckVersion" variant="outline" size="sm" :disabled="isCheckingVersion || !canCheck" class="w-full">
<RefreshCw class="mr-2 h-4 w-4" :class="{ 'animate-spin': isCheckingVersion }" />
<template v-if="isCheckingVersion">{{ t('settings.checking') }}</template>
<template v-else-if="!canCheck && cooldownTime">{{ cooldownTime }}</template>
<template v-else>{{ t('settings.checkUpdate') }}</template>
</Button>
</div>
</div>
<!-- 社区链接 -->
@@ -127,11 +152,14 @@
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<!-- 更新对话框 -->
<UpdateDialog v-model:open="showUpdateDialog" :version-info="updateInfo" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { useGameStore } from '@/stores/gameStore'
import { useI18n } from '@/composables/useI18n'
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
@@ -146,23 +174,64 @@
AlertDialogHeader,
AlertDialogTitle
} from '@/components/ui/alert-dialog'
import { Download, Upload, Trash2, ExternalLink, MessagesSquare, Play, Pause } from 'lucide-vue-next'
import { Download, Upload, Trash2, ExternalLink, MessagesSquare, Play, Pause, RefreshCw } from 'lucide-vue-next'
import { saveAs } from 'file-saver'
import { toast } from 'vue-sonner'
import pkg from '../../package.json'
import 'vue-sonner/style.css'
import { checkLatestVersion, canCheckVersion } from '@/utils/versionCheck'
import type { VersionInfo } from '@/utils/versionCheck'
import UpdateDialog from '@/components/UpdateDialog.vue'
const { t } = useI18n()
const gameStore = useGameStore()
const fileInputRef = ref<HTMLInputElement>()
const isExporting = ref(false)
const isCheckingVersion = ref(false)
const cooldownTime = ref('')
const showConfirmDialog = ref(false)
const confirmTitle = ref('')
const confirmMessage = ref('')
let confirmCallback: (() => void) | null = null
// 计算是否可以检查版本主动检测5分钟内不能重复检查
const canCheck = computed(() => canCheckVersion(gameStore.player.lastManualUpdateCheck || 0))
// 计算剩余冷却时间
const updateCooldownTime = () => {
if (canCheck.value) {
cooldownTime.value = ''
return
}
const lastCheck = gameStore.player.lastManualUpdateCheck || 0
const now = Date.now()
const fiveMinutes = 5 * 60 * 1000
const timePassed = now - lastCheck
const timeRemaining = fiveMinutes - timePassed
if (timeRemaining <= 0) {
cooldownTime.value = ''
return
}
const minutes = Math.floor(timeRemaining / 60000)
const seconds = Math.floor((timeRemaining % 60000) / 1000)
cooldownTime.value = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
}
// 每秒更新倒计时
let cooldownInterval: ReturnType<typeof setInterval> | null = null
onMounted(() => {
updateCooldownTime()
cooldownInterval = setInterval(updateCooldownTime, 1000)
})
onUnmounted(() => {
if (cooldownInterval) clearInterval(cooldownInterval)
})
const openGithub = () => {
window.open(`https://github.com/${pkg.author.name}/${pkg.name}`, '_blank')
}
@@ -171,6 +240,32 @@
window.open(`https://qm.qq.com/q/${pkg.id}`, '_blank')
}
// 手动检查版本
const showUpdateDialog = ref(false)
const updateInfo = ref<VersionInfo | null>(null)
const handleCheckVersion = async () => {
if (isCheckingVersion.value || !canCheck.value) return
isCheckingVersion.value = true
try {
const versionInfo = await checkLatestVersion(gameStore.player.lastManualUpdateCheck || 0, (time: number) => {
gameStore.player.lastManualUpdateCheck = time
})
if (versionInfo) {
updateInfo.value = versionInfo
showUpdateDialog.value = true
} else {
toast.success(t('settings.upToDate'))
}
} catch (error) {
console.error('Failed to check for updates:', error)
toast.error(t('settings.checkUpdateFailed'))
} finally {
isCheckingVersion.value = false
}
}
// 导出数据(包含游戏数据和地图数据)
const handleExport = async () => {
try {
@@ -281,10 +376,37 @@
}
const clearData = () => {
// 清除localStorage
localStorage.clear()
// 重新加载页面
window.location.reload()
gameStore.isPaused = true
try {
localStorage.clear()
window.location.reload()
} catch (error) {
console.error('Failed to clear data:', error)
// 即使出错也尝试重新加载
window.location.reload()
}
}
// 增加游戏倍率
const increaseSpeed = () => {
if (gameStore.gameSpeed < 10) {
gameStore.gameSpeed = Math.min(10, gameStore.gameSpeed + 0.5)
toast.success(t('settings.speedChanged', { speed: gameStore.gameSpeed }))
}
}
// 减少游戏倍率
const decreaseSpeed = () => {
if (gameStore.gameSpeed > 0.5) {
gameStore.gameSpeed = Math.max(0.5, gameStore.gameSpeed - 0.5)
toast.success(t('settings.speedChanged', { speed: gameStore.gameSpeed }))
}
}
// 重置游戏倍率
const resetSpeed = () => {
gameStore.gameSpeed = 1
toast.success(t('settings.speedReset'))
}
// 切换游戏暂停状态