feat(game): match Ref nation basic card
This commit is contained in:
@@ -1,86 +1,296 @@
|
||||
<script setup lang="ts">
|
||||
import SkeletonLines from '../ui/SkeletonLines.vue';
|
||||
import { legacyNationTextColor } from '../../utils/legacyNationColor';
|
||||
import { formatOfficerLevelText } from '../../utils/nationFormat';
|
||||
import { getNpcColor } from '../../utils/npcColor';
|
||||
|
||||
interface NationChief {
|
||||
id: number;
|
||||
name: string;
|
||||
npcState: number;
|
||||
}
|
||||
|
||||
interface NationInfo {
|
||||
id: number;
|
||||
name: string;
|
||||
color: string;
|
||||
level: number;
|
||||
levelName: string;
|
||||
gold: number;
|
||||
rice: number;
|
||||
tech: number;
|
||||
typeCode: string;
|
||||
typeName: string;
|
||||
capitalCityId: number | null;
|
||||
capitalCityName: string | null;
|
||||
typePros: string;
|
||||
typeCons: string;
|
||||
population: { cityCount: number; current: number; max: number };
|
||||
crew: { generalCount: number; current: number; max: number };
|
||||
power: number;
|
||||
bill: number;
|
||||
taxRate: number;
|
||||
strategicCommandLimit: number;
|
||||
diplomaticLimit: number;
|
||||
prohibitScout: boolean;
|
||||
prohibitWar: boolean;
|
||||
techLevel: number;
|
||||
techLimited: boolean;
|
||||
topChiefs: Record<number, NationChief | undefined>;
|
||||
impossibleStrategicCommands: Array<{
|
||||
name: string;
|
||||
remainingTurns: number;
|
||||
availableYear: number;
|
||||
availableMonth: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
nation: NationInfo | null;
|
||||
loading: boolean;
|
||||
}>();
|
||||
|
||||
const number = (value: number): string => value.toLocaleString('ko-KR');
|
||||
const displayChiefName = (chief: NationChief | undefined): string => {
|
||||
if (!chief) return '-';
|
||||
return chief.npcState > 0 && !/^[ⓜⓝ㉥]/u.test(chief.name) ? `ⓝ${chief.name}` : chief.name;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="nation-card">
|
||||
<div v-if="props.loading">
|
||||
<SkeletonLines :lines="4" />
|
||||
</div>
|
||||
<div class="nation-card" data-nation-basic-card>
|
||||
<div v-if="props.loading" class="loading"><SkeletonLines :lines="6" /></div>
|
||||
<div v-else-if="!props.nation" class="empty">국가 정보를 불러오지 못했습니다.</div>
|
||||
<div v-else class="nation-body">
|
||||
<div v-else class="nation-grid">
|
||||
<div
|
||||
class="title"
|
||||
:style="{ backgroundColor: props.nation.color, color: legacyNationTextColor(props.nation.color) }"
|
||||
>
|
||||
{{ props.nation.name }}<template v-if="props.nation.id > 0"> ({{ props.nation.levelName }})</template>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<span>국고</span
|
||||
><strong>{{ props.nation.id === 0 ? '해당 없음' : props.nation.gold.toLocaleString() }}</strong>
|
||||
<span>국량</span
|
||||
><strong>{{ props.nation.id === 0 ? '해당 없음' : props.nation.rice.toLocaleString() }}</strong>
|
||||
<span>기술</span
|
||||
><strong>{{ props.nation.id === 0 ? '해당 없음' : props.nation.tech.toLocaleString() }}</strong>
|
||||
<span>체제</span><strong>{{ props.nation.id === 0 ? '해당 없음' : props.nation.typeName }}</strong>
|
||||
<span>수도</span
|
||||
><strong>{{ props.nation.id === 0 ? '해당 없음' : (props.nation.capitalCityName ?? '-') }}</strong>
|
||||
<span>국가 등급</span
|
||||
><strong>{{ props.nation.id === 0 ? '해당 없음' : props.nation.levelName }}</strong>
|
||||
{{ props.nation.name }}
|
||||
</div>
|
||||
|
||||
<span class="head">성향</span>
|
||||
<strong class="body type-body">
|
||||
{{ props.nation.typeName }} (<span class="pros">{{ props.nation.typePros }}</span>
|
||||
<span class="cons">{{ props.nation.typeCons }}</span
|
||||
>)
|
||||
</strong>
|
||||
|
||||
<span class="head">{{ formatOfficerLevelText(12, props.nation.level) }}</span>
|
||||
<strong class="body" :style="{ color: getNpcColor(props.nation.topChiefs[12]?.npcState ?? 1) }">
|
||||
{{ displayChiefName(props.nation.topChiefs[12]) }}
|
||||
</strong>
|
||||
<span class="head">{{ formatOfficerLevelText(11, props.nation.level) }}</span>
|
||||
<strong class="body" :style="{ color: getNpcColor(props.nation.topChiefs[11]?.npcState ?? 1) }">
|
||||
{{ displayChiefName(props.nation.topChiefs[11]) }}
|
||||
</strong>
|
||||
|
||||
<span class="head">총 주민</span>
|
||||
<strong class="body">{{
|
||||
props.nation.id === 0
|
||||
? '해당 없음'
|
||||
: `${number(props.nation.population.current)} / ${number(props.nation.population.max)}`
|
||||
}}</strong>
|
||||
<span class="head">총 병사</span>
|
||||
<strong class="body">{{
|
||||
props.nation.id === 0
|
||||
? '해당 없음'
|
||||
: `${number(props.nation.crew.current)} / ${number(props.nation.crew.max)}`
|
||||
}}</strong>
|
||||
|
||||
<span class="head">국고</span>
|
||||
<strong class="body">{{ props.nation.id === 0 ? '해당 없음' : number(props.nation.gold) }}</strong>
|
||||
<span class="head">병량</span>
|
||||
<strong class="body">{{ props.nation.id === 0 ? '해당 없음' : number(props.nation.rice) }}</strong>
|
||||
|
||||
<span class="head">지급률</span>
|
||||
<strong class="body">{{ props.nation.id === 0 ? '해당 없음' : `${props.nation.bill}%` }}</strong>
|
||||
<span class="head">세율</span>
|
||||
<strong class="body">{{ props.nation.id === 0 ? '해당 없음' : `${props.nation.taxRate}%` }}</strong>
|
||||
|
||||
<span class="head">속령</span>
|
||||
<strong class="body">{{
|
||||
props.nation.id === 0 ? '해당 없음' : number(props.nation.population.cityCount)
|
||||
}}</strong>
|
||||
<span class="head">장수</span>
|
||||
<strong class="body">{{
|
||||
props.nation.id === 0 ? '해당 없음' : number(props.nation.crew.generalCount)
|
||||
}}</strong>
|
||||
|
||||
<span class="head">국력</span>
|
||||
<strong class="body">{{ props.nation.id === 0 ? '해당 없음' : number(props.nation.power) }}</strong>
|
||||
<span class="head">기술력</span>
|
||||
<strong class="body">
|
||||
<template v-if="props.nation.id === 0">해당 없음</template>
|
||||
<template v-else>
|
||||
{{ props.nation.techLevel }}등급 /
|
||||
<span :class="props.nation.techLimited ? 'tech-limited' : 'available'">{{
|
||||
number(Math.floor(props.nation.tech))
|
||||
}}</span>
|
||||
</template>
|
||||
</strong>
|
||||
|
||||
<span class="head">전략</span>
|
||||
<strong
|
||||
class="body strategic"
|
||||
:class="{ 'has-tooltip': props.nation.impossibleStrategicCommands.length > 0 }"
|
||||
:tabindex="props.nation.impossibleStrategicCommands.length > 0 ? 0 : undefined"
|
||||
>
|
||||
<template v-if="props.nation.id === 0">해당 없음</template>
|
||||
<span v-else-if="props.nation.strategicCommandLimit" class="blocked"
|
||||
>{{ number(props.nation.strategicCommandLimit) }}턴</span
|
||||
>
|
||||
<span v-else :class="props.nation.impossibleStrategicCommands.length > 0 ? 'warning' : 'available'"
|
||||
>가능</span
|
||||
>
|
||||
<span
|
||||
v-if="props.nation.impossibleStrategicCommands.length > 0"
|
||||
class="cooldown-tooltip"
|
||||
role="tooltip"
|
||||
>
|
||||
<span v-for="command in props.nation.impossibleStrategicCommands" :key="command.name">
|
||||
{{ command.name }}: {{ number(command.remainingTurns) }}턴 뒤({{ command.availableYear }}년
|
||||
{{ command.availableMonth }}월부터)
|
||||
</span>
|
||||
</span>
|
||||
</strong>
|
||||
<span class="head">외교</span>
|
||||
<strong class="body">
|
||||
<template v-if="props.nation.id === 0">해당 없음</template>
|
||||
<span v-else-if="props.nation.diplomaticLimit" class="blocked"
|
||||
>{{ number(props.nation.diplomaticLimit) }}턴</span
|
||||
>
|
||||
<span v-else class="available">가능</span>
|
||||
</strong>
|
||||
|
||||
<span class="head">임관</span>
|
||||
<strong class="body">
|
||||
<template v-if="props.nation.id === 0">해당 없음</template>
|
||||
<span v-else :class="props.nation.prohibitScout ? 'blocked' : 'available'">{{
|
||||
props.nation.prohibitScout ? '금지' : '허가'
|
||||
}}</span>
|
||||
</strong>
|
||||
<span class="head">전쟁</span>
|
||||
<strong class="body">
|
||||
<template v-if="props.nation.id === 0">해당 없음</template>
|
||||
<span v-else :class="props.nation.prohibitWar ? 'blocked' : 'available'">{{
|
||||
props.nation.prohibitWar ? '금지' : '허가'
|
||||
}}</span>
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
min-height: 24px;
|
||||
padding: 2px 6px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
.nation-card {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 193px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
}
|
||||
.grid > * {
|
||||
min-height: 23px;
|
||||
|
||||
.nation-grid {
|
||||
display: grid;
|
||||
box-sizing: border-box;
|
||||
border-right: 1px solid #666;
|
||||
border-bottom: 1px solid #666;
|
||||
padding: 2px 5px;
|
||||
width: 100%;
|
||||
height: 193px;
|
||||
grid-template-columns: 14% 36% 14% 36%;
|
||||
grid-template-rows: repeat(10, calc(192px / 10));
|
||||
border-right: 1px solid gray;
|
||||
border-bottom: 1px solid gray;
|
||||
background-color: #172a52;
|
||||
background-image: var(--sammo-texture-blue);
|
||||
}
|
||||
.grid > span {
|
||||
background: rgb(20 75 42 / 70%);
|
||||
|
||||
.nation-grid > * {
|
||||
box-sizing: border-box;
|
||||
min-width: 0;
|
||||
border-top: 1px solid gray;
|
||||
border-left: 1px solid gray;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
line-height: calc(193px / 10);
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.grid > strong {
|
||||
text-align: right;
|
||||
|
||||
.title {
|
||||
grid-column: 1 / 5;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.head {
|
||||
background-color: rgb(20 75 42 / 70%);
|
||||
}
|
||||
|
||||
.body {
|
||||
position: relative;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.type-body {
|
||||
grid-column: 2 / 5;
|
||||
}
|
||||
|
||||
.pros {
|
||||
color: cyan;
|
||||
}
|
||||
|
||||
.cons,
|
||||
.tech-limited {
|
||||
color: magenta;
|
||||
}
|
||||
|
||||
.blocked {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.available {
|
||||
color: limegreen;
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.strategic.has-tooltip {
|
||||
overflow: visible;
|
||||
text-decoration: underline dashed red;
|
||||
}
|
||||
|
||||
.cooldown-tooltip {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
bottom: calc(100% + 3px);
|
||||
left: 50%;
|
||||
display: none;
|
||||
width: max-content;
|
||||
max-width: 280px;
|
||||
transform: translateX(-50%);
|
||||
border: 1px solid #888;
|
||||
padding: 4px 7px;
|
||||
background: #111;
|
||||
color: #fff;
|
||||
line-height: 1.35;
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.cooldown-tooltip > span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.has-tooltip:hover .cooldown-tooltip,
|
||||
.has-tooltip:focus .cooldown-tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.empty {
|
||||
box-sizing: border-box;
|
||||
min-height: 193px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: rgba(232, 221, 196, 0.6);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user