mirror of
https://github.com/setube/ogame-vue-ts.git
synced 2026-05-12 07:55:11 +08:00
feat: 新增Android平台支持及构建流程
集成Android平台相关目录与配置文件,包含Gradle构建脚本、资源文件、启动图标、Java入口、Proguard规则等,完善.gitignore以排除Android构建产物。更新CI流程,支持自动构建并发布Android APK。移除README中项目结构说明,简化文档。
This commit is contained in:
@@ -157,7 +157,7 @@
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Empty, EmptyContent, EmptyDescription } from '@/components/ui/empty'
|
||||
import { Siren, Eye, Sword, Shield, Globe } from 'lucide-vue-next'
|
||||
import { Siren, Eye, Sword, Shield, Globe, Recycle } from 'lucide-vue-next'
|
||||
import { MissionType } from '@/types/game'
|
||||
import type { IncomingFleetAlert } from '@/types/game'
|
||||
import { formatDate, formatTime } from '@/utils/format'
|
||||
@@ -200,6 +200,8 @@
|
||||
return Eye
|
||||
case MissionType.Attack:
|
||||
return Sword
|
||||
case MissionType.Recycle:
|
||||
return Recycle
|
||||
default:
|
||||
return Siren
|
||||
}
|
||||
@@ -212,6 +214,8 @@
|
||||
return 'text-purple-500'
|
||||
case MissionType.Attack:
|
||||
return 'text-red-500'
|
||||
case MissionType.Recycle:
|
||||
return 'text-amber-500'
|
||||
default:
|
||||
return 'text-yellow-500'
|
||||
}
|
||||
@@ -229,6 +233,8 @@
|
||||
return t('enemyAlert.missionType.spy')
|
||||
case MissionType.Attack:
|
||||
return t('enemyAlert.missionType.attack')
|
||||
case MissionType.Recycle:
|
||||
return t('enemyAlert.missionType.recycle')
|
||||
default:
|
||||
return t('enemyAlert.missionType.unknown')
|
||||
}
|
||||
@@ -241,6 +247,8 @@
|
||||
return t('enemyAlert.warning.spy')
|
||||
case MissionType.Attack:
|
||||
return t('enemyAlert.warning.attack')
|
||||
case MissionType.Recycle:
|
||||
return t('enemyAlert.warning.recycle')
|
||||
default:
|
||||
return t('enemyAlert.warning.unknown')
|
||||
}
|
||||
|
||||
72
src/components/LowEnergyWarning.vue
Normal file
72
src/components/LowEnergyWarning.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div v-if="showWarning" class="bg-destructive/10 border-b border-destructive/20">
|
||||
<div class="px-4 sm:px-6 py-2 flex items-center justify-between gap-3">
|
||||
<!-- 警告图标和信息 -->
|
||||
<div class="flex items-center gap-2 flex-1 min-w-0">
|
||||
<Zap class="h-5 w-5 text-destructive flex-shrink-0 animate-pulse" />
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-semibold text-destructive">
|
||||
{{ t('energy.lowWarning') }}
|
||||
</p>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ detailMessage }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 建造电站按钮 -->
|
||||
<Button @click="goToBuildSolarPlant" variant="outline" size="sm" class="flex-shrink-0">
|
||||
{{ t('energy.buildSolarPlant') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGameStore } from '@/stores/gameStore'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Zap } from 'lucide-vue-next'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import * as resourceLogic from '@/logic/resourceLogic'
|
||||
import * as officerLogic from '@/logic/officerLogic'
|
||||
|
||||
const gameStore = useGameStore()
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
// 获取当前星球
|
||||
const planet = computed(() => gameStore.currentPlanet)
|
||||
|
||||
// 计算能量产量
|
||||
const energyProduction = computed(() => {
|
||||
if (!planet.value) return 0
|
||||
const now = Date.now()
|
||||
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
|
||||
return resourceLogic.calculateEnergyProduction(planet.value, { energyProductionBonus: bonuses.energyProductionBonus })
|
||||
})
|
||||
|
||||
// 计算能量消耗
|
||||
const energyConsumption = computed(() => {
|
||||
if (!planet.value) return 0
|
||||
return resourceLogic.calculateEnergyConsumption(planet.value)
|
||||
})
|
||||
|
||||
// 是否显示警告(电力产量 < 消耗)
|
||||
const showWarning = computed(() => {
|
||||
if (!planet.value) return false
|
||||
return energyProduction.value < energyConsumption.value
|
||||
})
|
||||
|
||||
// 详细消息
|
||||
const detailMessage = computed(() => {
|
||||
const deficit = Math.ceil(energyConsumption.value - energyProduction.value)
|
||||
return t('energy.deficitDetail', { deficit: deficit.toString() })
|
||||
})
|
||||
|
||||
// 跳转到建筑页面建造太阳能电站
|
||||
const goToBuildSolarPlant = () => {
|
||||
router.push('/buildings')
|
||||
}
|
||||
</script>
|
||||
@@ -4,12 +4,20 @@
|
||||
<CardHeader>
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<CardTitle class="flex items-center gap-2">
|
||||
<CardTitle class="flex items-center gap-2 flex-wrap">
|
||||
{{ npc.name }}
|
||||
<span v-if="npc.note" class="text-muted-foreground font-normal">({{ npc.note }})</span>
|
||||
<Badge :variant="statusBadgeVariant">
|
||||
{{ statusText }}
|
||||
</Badge>
|
||||
<!-- NPC难度等级徽章 -->
|
||||
<Badge
|
||||
v-if="npc.difficultyLevel"
|
||||
:variant="difficultyBadgeVariant"
|
||||
:class="difficultyLevelColor"
|
||||
>
|
||||
Lv.{{ npc.difficultyLevel }}
|
||||
</Badge>
|
||||
</CardTitle>
|
||||
<CardDescription class="mt-1">
|
||||
{{ npc.planets.length }} {{ t('diplomacy.planets') }}
|
||||
@@ -208,6 +216,28 @@
|
||||
return 'text-muted-foreground'
|
||||
})
|
||||
|
||||
// NPC难度等级颜色
|
||||
const difficultyLevelColor = computed(() => {
|
||||
const level = props.npc.difficultyLevel
|
||||
if (!level) return 'text-muted-foreground'
|
||||
if (level <= 1) return 'text-green-600 dark:text-green-400' // 新手
|
||||
if (level <= 2) return 'text-lime-600 dark:text-lime-400' // 简单
|
||||
if (level <= 3) return 'text-yellow-600 dark:text-yellow-400' // 普通
|
||||
if (level <= 4) return 'text-orange-600 dark:text-orange-400' // 困难
|
||||
if (level <= 5) return 'text-red-600 dark:text-red-400' // 专家
|
||||
if (level <= 6) return 'text-purple-600 dark:text-purple-400' // 大师
|
||||
return 'text-pink-600 dark:text-pink-400' // 传奇及以上
|
||||
})
|
||||
|
||||
// NPC难度等级Badge样式
|
||||
const difficultyBadgeVariant = computed((): 'default' | 'secondary' | 'destructive' | 'outline' => {
|
||||
const level = props.npc.difficultyLevel
|
||||
if (!level) return 'outline'
|
||||
if (level <= 2) return 'secondary'
|
||||
if (level <= 4) return 'default'
|
||||
return 'destructive'
|
||||
})
|
||||
|
||||
// 最近的外交事件
|
||||
const recentEvent = computed(() => {
|
||||
if (!props.relation?.history || props.relation.history.length === 0) return null
|
||||
|
||||
@@ -18,6 +18,15 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium truncate">{{ npc.name }}</span>
|
||||
<span v-if="npc.note" class="text-muted-foreground text-sm truncate">({{ npc.note }})</span>
|
||||
<!-- NPC难度等级徽章 -->
|
||||
<Badge
|
||||
v-if="npc.difficultyLevel"
|
||||
:variant="difficultyBadgeVariant"
|
||||
class="text-xs"
|
||||
:class="difficultyLevelColor"
|
||||
>
|
||||
Lv.{{ npc.difficultyLevel }}
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="text-xs text-muted-foreground">
|
||||
{{ npc.planets.length }} {{ t('diplomacy.planets') }}
|
||||
@@ -68,9 +77,18 @@
|
||||
'bg-gray-400': status === RelationStatus.Neutral
|
||||
}"
|
||||
/>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex-1 min-w-0 flex items-center gap-1 flex-wrap">
|
||||
<span class="font-medium truncate">{{ npc.name }}</span>
|
||||
<span v-if="npc.note" class="text-muted-foreground text-sm ml-1">({{ npc.note }})</span>
|
||||
<span v-if="npc.note" class="text-muted-foreground text-sm">({{ npc.note }})</span>
|
||||
<!-- NPC难度等级徽章 (移动端) -->
|
||||
<Badge
|
||||
v-if="npc.difficultyLevel"
|
||||
:variant="difficultyBadgeVariant"
|
||||
class="text-xs"
|
||||
:class="difficultyLevelColor"
|
||||
>
|
||||
Lv.{{ npc.difficultyLevel }}
|
||||
</Badge>
|
||||
</div>
|
||||
<ChevronDown class="h-4 w-4 text-muted-foreground transition-transform flex-shrink-0" :class="{ 'rotate-180': isExpanded }" />
|
||||
</div>
|
||||
@@ -214,6 +232,28 @@
|
||||
return 'text-muted-foreground'
|
||||
})
|
||||
|
||||
// NPC难度等级颜色
|
||||
const difficultyLevelColor = computed(() => {
|
||||
const level = props.npc.difficultyLevel
|
||||
if (!level) return 'text-muted-foreground'
|
||||
if (level <= 1) return 'text-green-600 dark:text-green-400' // 新手
|
||||
if (level <= 2) return 'text-lime-600 dark:text-lime-400' // 简单
|
||||
if (level <= 3) return 'text-yellow-600 dark:text-yellow-400' // 普通
|
||||
if (level <= 4) return 'text-orange-600 dark:text-orange-400' // 困难
|
||||
if (level <= 5) return 'text-red-600 dark:text-red-400' // 专家
|
||||
if (level <= 6) return 'text-purple-600 dark:text-purple-400' // 大师
|
||||
return 'text-pink-600 dark:text-pink-400' // 传奇及以上
|
||||
})
|
||||
|
||||
// NPC难度等级Badge样式
|
||||
const difficultyBadgeVariant = computed((): 'default' | 'secondary' | 'destructive' | 'outline' => {
|
||||
const level = props.npc.difficultyLevel
|
||||
if (!level) return 'outline'
|
||||
if (level <= 2) return 'secondary'
|
||||
if (level <= 4) return 'default'
|
||||
return 'destructive'
|
||||
})
|
||||
|
||||
// 最近的外交事件
|
||||
const recentEvent = computed(() => {
|
||||
if (!props.relation?.history || props.relation.history.length === 0) return null
|
||||
|
||||
@@ -173,7 +173,8 @@
|
||||
const getQueueProgress = (item: BuildQueueItem): number => {
|
||||
const elapsed = currentTime.value - item.startTime
|
||||
const total = item.endTime - item.startTime
|
||||
return Math.min(100, (elapsed / total) * 100)
|
||||
if (total <= 0) return 100
|
||||
return Math.max(0, Math.min(100, (elapsed / total) * 100))
|
||||
}
|
||||
|
||||
// 统一的取消处理
|
||||
|
||||
Reference in New Issue
Block a user