feat: 新增队列与外交通知组件及新手引导

引入队列通知(QueueNotifications)和外交通知(DiplomaticNotifications)组件,优化主界面队列与外交报告展示,支持一键查看与跳转。重构App.vue,移除原有队列展示,改为弹出式通知,支持功能解锁提示与新手引导(TutorialOverlay)。完善NPC外交事件处理,导弹攻击等行为影响好感度并生成报告。优化部分UI细节与多语言文本,提升交互体验。
This commit is contained in:
谦君
2025-12-17 21:06:34 +08:00
parent 053bd24855
commit cfcde0b024
38 changed files with 3605 additions and 420 deletions

View File

@@ -0,0 +1,562 @@
import { ref, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useGameStore } from '@/stores/gameStore'
import type { TutorialStep, TutorialState } from '@/types/game'
import { BuildingType, TechnologyType } from '@/types/game'
// 桌面端引导步骤定义
export const desktopTutorialSteps: TutorialStep[] = [
// 第1步欢迎和基础介绍
{
id: 'welcome',
title: 'tutorial.welcome.title',
content: 'tutorial.welcome.content',
placement: 'center',
route: '/',
action: 'none',
canSkip: true
},
// 第2步资源栏介绍
{
id: 'resources_intro',
title: 'tutorial.resources.title',
content: 'tutorial.resources.content',
target: '.resource-bar',
placement: 'bottom',
route: '/',
action: 'none',
highlightPadding: 8
},
// 第3步星球选择器介绍
{
id: 'planet_info',
title: 'tutorial.planet.title',
content: 'tutorial.planet.content',
target: '[data-tutorial="planet-selector"]',
placement: 'bottom',
route: '/',
action: 'none',
highlightPadding: 8
},
// 第4步导航菜单介绍
{
id: 'navigation',
title: 'tutorial.navigation.title',
content: 'tutorial.navigation.content',
target: '[data-tutorial="navigation"]',
placement: 'right',
route: '/',
action: 'none',
highlightPadding: 12
},
// 第5步前往建筑页面
{
id: 'goto_buildings',
title: 'tutorial.gotoBuildings.title',
content: 'tutorial.gotoBuildings.content',
target: '[data-nav-path="/buildings"]',
placement: 'right',
route: '/',
action: 'click',
highlightPadding: 8
},
// 第6步建造太阳能电站提供能源是所有资源建筑的前置条件
{
id: 'build_solar_plant',
title: 'tutorial.buildSolarPlant.title',
content: 'tutorial.buildSolarPlant.content',
target: `[data-building="${BuildingType.SolarPlant}"]`,
placement: 'top',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.SolarPlant,
highlightPadding: 12
},
// 第7步了解建造队列
{
id: 'wait_for_build',
title: 'tutorial.waitBuild.title',
content: 'tutorial.waitBuild.content',
target: '[data-tutorial="queue-button"]',
placement: 'bottom',
route: '/buildings',
action: 'none',
highlightPadding: 8
},
// 第8步建造金属矿有了太阳能电站后才能建造
{
id: 'build_metal_mine',
title: 'tutorial.buildMetalMine.title',
content: 'tutorial.buildMetalMine.content',
target: `[data-building="${BuildingType.MetalMine}"]`,
placement: 'top',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.MetalMine,
highlightPadding: 12
},
// 第9步建造晶体矿
{
id: 'build_crystal_mine',
title: 'tutorial.buildCrystalMine.title',
content: 'tutorial.buildCrystalMine.content',
target: `[data-building="${BuildingType.CrystalMine}"]`,
placement: 'top',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.CrystalMine,
highlightPadding: 12
},
// 第10步建造重氢合成器
{
id: 'build_deuterium',
title: 'tutorial.buildDeuterium.title',
content: 'tutorial.buildDeuterium.content',
target: `[data-building="${BuildingType.DeuteriumSynthesizer}"]`,
placement: 'top',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.DeuteriumSynthesizer,
highlightPadding: 12
},
// 第11步升级资源矿到2级为机器人工厂做准备
{
id: 'upgrade_mines_intro',
title: 'tutorial.upgradeMines.title',
content: 'tutorial.upgradeMines.content',
placement: 'center',
route: '/buildings',
action: 'none'
},
// 第12步建造机器人工厂需要三种资源矿各2级
{
id: 'build_robotics',
title: 'tutorial.buildRobotics.title',
content: 'tutorial.buildRobotics.content',
target: `[data-building="${BuildingType.RoboticsFactory}"]`,
placement: 'top',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.RoboticsFactory,
highlightPadding: 12
},
// 第13步继续升级资源矿到3级为研究实验室做准备
{
id: 'upgrade_mines_for_lab',
title: 'tutorial.upgradeMinesForLab.title',
content: 'tutorial.upgradeMinesForLab.content',
placement: 'center',
route: '/buildings',
action: 'none'
},
// 第14步建造研究实验室需要三种资源矿各3级
{
id: 'build_research_lab',
title: 'tutorial.buildResearchLab.title',
content: 'tutorial.buildResearchLab.content',
target: `[data-building="${BuildingType.ResearchLab}"]`,
placement: 'top',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.ResearchLab,
highlightPadding: 12
},
// 第15步前往研究页面
{
id: 'goto_research',
title: 'tutorial.gotoResearch.title',
content: 'tutorial.gotoResearch.content',
target: '[data-nav-path="/research"]',
placement: 'right',
route: '/buildings',
action: 'click',
highlightPadding: 8
},
// 第16步研究能量科技
{
id: 'research_energy',
title: 'tutorial.researchEnergy.title',
content: 'tutorial.researchEnergy.content',
target: `[data-tech="${TechnologyType.EnergyTechnology}"]`,
placement: 'top',
route: '/research',
action: 'research',
actionTarget: TechnologyType.EnergyTechnology,
highlightPadding: 12
},
// 第17步介绍船坞需要机器人工厂2级
{
id: 'shipyard_intro',
title: 'tutorial.shipyardIntro.title',
content: 'tutorial.shipyardIntro.content',
placement: 'center',
route: '/research',
action: 'none'
},
// 第18步返回建筑页面建造船坞
{
id: 'goto_buildings_for_shipyard',
title: 'tutorial.gotoBuildingsForShipyard.title',
content: 'tutorial.gotoBuildingsForShipyard.content',
target: '[data-nav-path="/buildings"]',
placement: 'right',
route: '/research',
action: 'click',
highlightPadding: 8
},
// 第19步建造船坞
{
id: 'build_shipyard',
title: 'tutorial.buildShipyard.title',
content: 'tutorial.buildShipyard.content',
target: `[data-building="${BuildingType.Shipyard}"]`,
placement: 'top',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.Shipyard,
highlightPadding: 12
},
// 第20步舰队和探索介绍
{
id: 'fleet_intro',
title: 'tutorial.fleetIntro.title',
content: 'tutorial.fleetIntro.content',
placement: 'center',
route: '/buildings',
action: 'none'
},
// 第21步银河系探索介绍
{
id: 'galaxy_intro',
title: 'tutorial.galaxyIntro.title',
content: 'tutorial.galaxyIntro.content',
target: '[data-nav-path="/galaxy"]',
placement: 'right',
route: '/buildings',
action: 'none',
highlightPadding: 8
},
// 第22步引导完成
{
id: 'tutorial_complete',
title: 'tutorial.complete.title',
content: 'tutorial.complete.content',
placement: 'center',
route: '/buildings',
action: 'none'
}
]
// 移动端引导步骤定义
export const mobileTutorialSteps: TutorialStep[] = [
// 第1步欢迎移动端
{
id: 'welcome_mobile',
title: 'tutorial.mobile.welcome.title',
content: 'tutorial.mobile.welcome.content',
placement: 'center',
route: '/',
action: 'none',
canSkip: true
},
// 第2步顶部资源栏介绍
{
id: 'resources_intro_mobile',
title: 'tutorial.mobile.resources.title',
content: 'tutorial.mobile.resources.content',
target: '.resource-bar',
placement: 'bottom',
route: '/',
action: 'none',
highlightPadding: 8
},
// 第3步汉堡菜单介绍 - 引导玩家手动点击打开菜单
{
id: 'menu_intro_mobile',
title: 'tutorial.mobile.menu.title',
content: 'tutorial.mobile.menu.content',
target: '[data-tutorial="mobile-menu"]',
placement: 'bottom',
route: '/',
action: 'none', // 让玩家手动点击汉堡菜单打开侧边栏
highlightPadding: 8
},
// 第4步:前往建筑页面 - 此时侧边栏已打开,让玩家手动点击
{
id: 'goto_buildings_mobile',
title: 'tutorial.mobile.gotoBuildings.title',
content: 'tutorial.mobile.gotoBuildings.content',
target: '[data-nav-path="/buildings"]',
placement: 'right', // 改为right,因为菜单在左侧展开
route: '/',
action: 'click', // 使用click,但不会自动触发,只是用来标识这是一个点击操作
highlightPadding: 8
},
// 第5步建造太阳能电站
{
id: 'build_solar_plant_mobile',
title: 'tutorial.mobile.buildSolarPlant.title',
content: 'tutorial.mobile.buildSolarPlant.content',
target: `[data-building="${BuildingType.SolarPlant}"]`,
placement: 'bottom',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.SolarPlant,
highlightPadding: 12
},
// 第6步了解建造队列
{
id: 'wait_for_build_mobile',
title: 'tutorial.mobile.waitBuild.title',
content: 'tutorial.mobile.waitBuild.content',
target: '[data-tutorial="queue-button"]',
placement: 'bottom',
route: '/buildings',
action: 'none',
highlightPadding: 8
},
// 第7步建造金属矿
{
id: 'build_metal_mine_mobile',
title: 'tutorial.mobile.buildMetalMine.title',
content: 'tutorial.mobile.buildMetalMine.content',
target: `[data-building="${BuildingType.MetalMine}"]`,
placement: 'bottom',
route: '/buildings',
action: 'build',
actionTarget: BuildingType.MetalMine,
highlightPadding: 12
},
// 第8步完成教程
{
id: 'tutorial_complete_mobile',
title: 'tutorial.mobile.complete.title',
content: 'tutorial.mobile.complete.content',
placement: 'center',
route: '/buildings',
action: 'none'
}
]
// 检测是否为移动端
const isMobileDevice = () => {
return window.innerWidth < 768
}
// 根据设备类型获取教程步骤
export const getTutorialSteps = (): TutorialStep[] => {
return isMobileDevice() ? mobileTutorialSteps : desktopTutorialSteps
}
// 导出统一的 tutorialSteps为了兼容性
export const tutorialSteps = getTutorialSteps()
const tutorialState = ref<TutorialState>({
isActive: false,
currentStepIndex: 0,
completedSteps: [],
skipped: false
})
export function useTutorial() {
const router = useRouter()
const gameStore = useGameStore()
// 动态获取教程步骤
const currentTutorialSteps = computed(() => getTutorialSteps())
const currentStep = computed(() => {
if (!tutorialState.value.isActive || tutorialState.value.currentStepIndex >= currentTutorialSteps.value.length) {
return null
}
return currentTutorialSteps.value[tutorialState.value.currentStepIndex]
})
const progress = computed(() => {
return Math.round((tutorialState.value.currentStepIndex / currentTutorialSteps.value.length) * 100)
})
const isLastStep = computed(() => {
return tutorialState.value.currentStepIndex === currentTutorialSteps.value.length - 1
})
// 初始化引导
const startTutorial = () => {
const player = gameStore.player
if (!player.tutorialProgress || !player.tutorialProgress.tutorialCompleted) {
const now = Date.now()
tutorialState.value = {
isActive: true,
currentStepIndex: 0,
completedSteps: player.tutorialProgress?.completedStepIds || [],
skipped: false,
lastActiveTime: now
}
// 如果有进度,恢复到上次的步骤
if (player.tutorialProgress?.currentStep) {
const stepIndex = currentTutorialSteps.value.findIndex((s: TutorialStep) => s.id === player.tutorialProgress?.currentStep)
if (stepIndex !== -1) {
tutorialState.value.currentStepIndex = stepIndex
}
}
// 跳转到当前步骤的路由
if (currentStep.value?.route) {
router.push(currentStep.value.route)
}
}
}
// 下一步
const nextStep = () => {
if (!currentStep.value) return
// 标记当前步骤为已完成
if (!tutorialState.value.completedSteps.includes(currentStep.value.id)) {
tutorialState.value.completedSteps.push(currentStep.value.id)
}
// 保存进度到store
saveProgress()
// 移动到下一步
if (tutorialState.value.currentStepIndex < currentTutorialSteps.value.length - 1) {
tutorialState.value.currentStepIndex++
// 跳转到新步骤的路由
if (currentStep.value?.route) {
router.push(currentStep.value.route)
}
} else {
// 引导完成
completeTutorial()
}
}
// 上一步
const previousStep = () => {
if (tutorialState.value.currentStepIndex > 0) {
tutorialState.value.currentStepIndex--
// 跳转到新步骤的路由
if (currentStep.value?.route) {
router.push(currentStep.value.route)
}
}
}
// 跳过引导
const skipTutorial = () => {
tutorialState.value.isActive = false
tutorialState.value.skipped = true
// 保存跳过状态(跳过也视为已完成,避免刷新后重新弹出)
if (!gameStore.player.tutorialProgress) {
gameStore.player.tutorialProgress = {
tutorialCompleted: true,
completedStepIds: tutorialState.value.completedSteps,
currentStep: null,
skippedAt: Date.now()
}
} else {
gameStore.player.tutorialProgress.tutorialCompleted = true
gameStore.player.tutorialProgress.skippedAt = Date.now()
gameStore.player.tutorialProgress.currentStep = null
}
}
// 完成引导
const completeTutorial = () => {
tutorialState.value.isActive = false
// 保存完成状态
gameStore.player.tutorialProgress = {
tutorialCompleted: true,
completedStepIds: tutorialState.value.completedSteps,
currentStep: null
}
}
// 保存进度
const saveProgress = () => {
if (!gameStore.player.tutorialProgress) {
gameStore.player.tutorialProgress = {
tutorialCompleted: false,
completedStepIds: [],
currentStep: null
}
}
gameStore.player.tutorialProgress.completedStepIds = [...tutorialState.value.completedSteps]
gameStore.player.tutorialProgress.currentStep = currentStep.value?.id || null
}
// 检查步骤完成条件
const checkStepCompletion = (stepId: string): boolean => {
const step = currentTutorialSteps.value.find((s: TutorialStep) => s.id === stepId)
if (!step) return false
const planet = gameStore.currentPlanet
if (!planet) return false
switch (step.action) {
case 'build':
if (step.actionTarget) {
// 简单检查队列中是否有该建筑
const inQueue = planet.buildQueue.some(
item => item.itemType === step.actionTarget && (item.type === 'building' || item.type === 'demolish')
)
return inQueue
}
return false
case 'research':
if (step.actionTarget) {
// 简单检查队列中是否有该科技
const inQueue = planet.buildQueue.some(item => item.itemType === step.actionTarget && item.type === 'technology')
return inQueue
}
return false
case 'click':
case 'none':
default:
return true
}
}
// 不再自动推进,完全由玩家手动点击"下一步"按钮控制
// 监听路由变化,自动推进需要导航的教程步骤
watch(
() => router.currentRoute.value.path,
newPath => {
if (tutorialState.value.isActive && currentStep.value) {
// 如果当前步骤需要导航到特定页面,且已经到达该页面,自动推进
if (currentStep.value.action === 'none' && currentStep.value.target && currentStep.value.target.includes('data-nav-path')) {
// 提取目标路径
const match = currentStep.value.target.match(/data-nav-path="([^"]+)"/)
if (match && match[1] === newPath) {
setTimeout(() => {
nextStep()
}, 500)
}
}
}
}
)
return {
tutorialState,
currentStep,
progress,
isLastStep,
startTutorial,
nextStep,
previousStep,
skipTutorial,
completeTutorial,
checkStepCompletion
}
}