refactor: 优化主界面布局与通知系统

重构App.vue,首页独立无侧边栏,其他页面采用统一侧边栏布局。新增右下角固定通知区,集成返回顶部、队列通知、外交通知和敌方警报。移除新手引导组件,替换为弱引导提示系统。支持星球重命名弹窗。优化NPC成长与行为定时器逻辑,提升性能和可维护性。删除issue模板及相关文档描述。
This commit is contained in:
谦君
2025-12-19 12:01:45 +08:00
parent a689ce21b7
commit 752cade67c
61 changed files with 5774 additions and 2817 deletions

239
src/composables/useHints.ts Normal file
View File

@@ -0,0 +1,239 @@
/**
* 弱引导系统 - 非阻塞式、可关闭的页面提示
* 用温和的引导替代强制性教程
*/
import { ref, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useGameStore } from '@/stores/gameStore'
// 提示定义 - 用户首次访问页面时显示一次
export interface Hint {
id: string
route: string // 显示此提示的路由路径
titleKey: string // 标题的 i18n 键
messageKey: string // 消息的 i18n 键
icon?: string // 可选的图标名称
delay?: number // 显示前的延迟毫秒数(默认 500
}
// 所有可用的提示
const hints: Hint[] = [
{
id: 'overview_intro',
route: '/overview',
titleKey: 'hints.overview.title',
messageKey: 'hints.overview.message',
icon: 'home',
delay: 1000
},
{
id: 'buildings_intro',
route: '/buildings',
titleKey: 'hints.buildings.title',
messageKey: 'hints.buildings.message',
icon: 'building',
delay: 500
},
{
id: 'research_intro',
route: '/research',
titleKey: 'hints.research.title',
messageKey: 'hints.research.message',
icon: 'flask',
delay: 500
},
{
id: 'shipyard_intro',
route: '/shipyard',
titleKey: 'hints.shipyard.title',
messageKey: 'hints.shipyard.message',
icon: 'rocket',
delay: 500
},
{
id: 'fleet_intro',
route: '/fleet',
titleKey: 'hints.fleet.title',
messageKey: 'hints.fleet.message',
icon: 'plane',
delay: 500
},
{
id: 'galaxy_intro',
route: '/galaxy',
titleKey: 'hints.galaxy.title',
messageKey: 'hints.galaxy.message',
icon: 'globe',
delay: 500
},
{
id: 'diplomacy_intro',
route: '/diplomacy',
titleKey: 'hints.diplomacy.title',
messageKey: 'hints.diplomacy.message',
icon: 'handshake',
delay: 500
},
{
id: 'messages_intro',
route: '/messages',
titleKey: 'hints.messages.title',
messageKey: 'hints.messages.message',
icon: 'mail',
delay: 500
},
{
id: 'defense_intro',
route: '/defense',
titleKey: 'hints.defense.title',
messageKey: 'hints.defense.message',
icon: 'shield',
delay: 500
},
{
id: 'officers_intro',
route: '/officers',
titleKey: 'hints.officers.title',
messageKey: 'hints.officers.message',
icon: 'users',
delay: 500
},
{
id: 'simulator_intro',
route: '/battle-simulator',
titleKey: 'hints.simulator.title',
messageKey: 'hints.simulator.message',
icon: 'swords',
delay: 500
},
{
id: 'settings_intro',
route: '/settings',
titleKey: 'hints.settings.title',
messageKey: 'hints.settings.message',
icon: 'settings',
delay: 500
},
{
id: 'gm_intro',
route: '/gm',
titleKey: 'hints.gm.title',
messageKey: 'hints.gm.message',
icon: 'wand',
delay: 500
}
]
// 全局UI状态不需要持久化
const currentHint = ref<Hint | null>(null)
const isHintVisible = ref(false)
let hintTimeout: ReturnType<typeof setTimeout> | null = null
export function useHints() {
const router = useRouter()
const gameStore = useGameStore()
// 确保 dismissedHints 数组已初始化
if (!gameStore.player.dismissedHints) {
gameStore.player.dismissedHints = []
}
// 确保 hintsEnabled 已初始化(默认为 true
if (gameStore.player.hintsEnabled === undefined) {
gameStore.player.hintsEnabled = true
}
// 检查提示是否已被关闭
const isHintDismissed = (hintId: string): boolean => {
return gameStore.player.dismissedHints?.includes(hintId) ?? false
}
// 检查当前路由是否应该显示提示
const checkForHint = (routePath: string) => {
if (!gameStore.player.hintsEnabled) return
// 清除任何待显示的提示
if (hintTimeout) {
clearTimeout(hintTimeout)
hintTimeout = null
}
// 导航时隐藏当前提示
isHintVisible.value = false
currentHint.value = null
// 查找此路由对应的提示
const hint = hints.find(h => routePath.startsWith(h.route))
if (!hint) return
// 检查是否已经关闭过
if (isHintDismissed(hint.id)) return
// 延迟后显示提示
const delay = hint.delay ?? 500
hintTimeout = setTimeout(() => {
currentHint.value = hint
isHintVisible.value = true
}, delay)
}
// 关闭当前提示(不再显示)
const dismissHint = (dontShowAgain = true) => {
if (currentHint.value && dontShowAgain) {
if (!gameStore.player.dismissedHints) {
gameStore.player.dismissedHints = []
}
if (!gameStore.player.dismissedHints.includes(currentHint.value.id)) {
gameStore.player.dismissedHints.push(currentHint.value.id)
}
}
isHintVisible.value = false
currentHint.value = null
}
// 暂时关闭提示(下次访问还会显示)
const closeHint = () => {
isHintVisible.value = false
currentHint.value = null
}
// 重置所有提示(重新显示)
const resetHints = () => {
gameStore.player.dismissedHints = []
}
// 切换提示开关
const setHintsEnabled = (enabled: boolean) => {
gameStore.player.hintsEnabled = enabled
if (!enabled) {
isHintVisible.value = false
currentHint.value = null
}
}
// 监听路由变化
watch(
() => router.currentRoute.value.path,
newPath => {
checkForHint(newPath)
},
{ immediate: true }
)
return {
// 状态
currentHint: computed(() => currentHint.value),
isHintVisible: computed(() => isHintVisible.value),
hintsEnabled: computed(() => gameStore.player.hintsEnabled ?? true),
dismissedCount: computed(() => gameStore.player.dismissedHints?.length ?? 0),
totalHints: computed(() => hints.length),
// 操作
dismissHint,
closeHint,
resetHints,
setHintsEnabled,
checkForHint
}
}