인게임 예약 명령과 장수 상태 표시를 바로잡음

This commit is contained in:
2026-09-04 19:16:56 +00:00
parent 5d220de739
commit 0157ff6a6b
31 changed files with 511 additions and 81 deletions
+16 -2
View File
@@ -1052,7 +1052,13 @@ onUnmounted(() => {
</div>
<form class="npc-card-holder" @submit.prevent>
<div v-for="npc in npcCandidates" :key="npc.id" class="npc-card">
<h4 class="npc-card-name">{{ npc.name }}</h4>
<h4
class="npc-card-name"
:class="{ 'npc-card-name--long': npc.name.length >= 9 }"
:title="npc.name"
>
{{ npc.name }}
</h4>
<h4>
<img
class="npc-card-image"
@@ -1723,10 +1729,18 @@ onUnmounted(() => {
}
.npc-card-name {
min-height: 25px;
box-sizing: border-box;
height: 25px;
overflow: hidden;
border: 1px solid rgba(201, 164, 90, 0.3);
font-size: 1rem;
line-height: 23px;
text-overflow: ellipsis;
white-space: nowrap;
}
.npc-card-name--long {
font-size: 0.75rem;
}
.npc-card-image {
+53 -9
View File
@@ -8,7 +8,7 @@ import PanelCard from '../components/ui/PanelCard.vue';
import SkeletonLines from '../components/ui/SkeletonLines.vue';
import MapViewer from '../components/main/MapViewer.vue';
import CommandListPanel from '../components/main/CommandListPanel.vue';
import GeneralBasicCard from '../components/main/GeneralBasicCard.vue';
import GeneralInformationPanel from '../components/main/GeneralInformationPanel.vue';
import CityBasicCard from '../components/main/CityBasicCard.vue';
import NationBasicCard from '../components/main/NationBasicCard.vue';
import MessagePanel from '../components/main/MessagePanel.vue';
@@ -100,6 +100,43 @@ const nationAccess = computed(() => ({
nationLevel: nation.value?.level ?? 0,
}));
const nationColor = computed(() => nation.value?.color ?? '#000000');
const generalPanel = computed(() => {
const current = general.value;
if (!current) return null;
return {
...current,
progression: {
experienceLevel: current.progression?.experienceLevel ?? 0,
dedicationLevel: current.progression?.dedicationLevel ?? 0,
dedicationText: current.progression?.dedicationText ?? '-',
statExperience: current.progression?.statExperience ?? {
leadership: 0,
strength: 0,
intelligence: 0,
},
statUpgradeLimit: current.progression?.statUpgradeLimit ?? 30,
dex: current.progression?.dex ?? [0, 0, 0, 0, 0],
},
};
});
const generalSummary = computed(() =>
general.value
? {
available: true,
experience: general.value.experience,
dedicationText: general.value.progression?.dedicationText,
bill: general.value.bill,
warnum: general.value.records?.battles,
wins: general.value.records?.wins,
losses: general.value.records?.losses,
strategies: general.value.records?.strategies,
serviceYears: general.value.records?.serviceYears,
killCrew: general.value.records?.killedCrew,
deathCrew: general.value.records?.lostCrew,
recentWar: general.value.recentWar,
}
: null
);
const voteActive = computed(() => Boolean(frontStatus.value?.latestVote));
const profileLabels: Record<string, string> = {
che: '체',
@@ -183,10 +220,7 @@ const shiftGeneralTurns = (amount: number) => {
void dashboard.shiftGeneralTurns(amount);
};
const reserveGeneralTurns = async (
entries: CommandPatternEntry[],
complete?: (success: boolean) => void
) => {
const reserveGeneralTurns = async (entries: CommandPatternEntry[], complete?: (success: boolean) => void) => {
const success = await dashboard.setGeneralTurns(entries);
complete?.(success);
};
@@ -322,7 +356,7 @@ watch(
:command-table="commandTable"
:loading="loading"
:reserved-general-turns="reservedGeneralTurns"
:general="general"
:general="generalPanel"
:current-year="lobbyInfo?.year"
:current-month="lobbyInfo?.month"
:turn-term-minutes="lobbyInfo?.turnTerm"
@@ -371,7 +405,12 @@ watch(
data-mobile-panel-id="general"
>
<PanelCard title="장수 스탯" hide-header aria-label="장수 정보" data-main-target="general">
<GeneralBasicCard :general="general" :loading="loading" :nation-color="nation?.color" />
<GeneralInformationPanel
:general="generalPanel"
:summary="generalSummary"
:loading="loading"
:nation-color="nation?.color"
/>
</PanelCard>
</div>
@@ -498,7 +537,7 @@ watch(
:command-table="commandTable"
:loading="loading"
:reserved-general-turns="reservedGeneralTurns"
:general="general"
:general="generalPanel"
:current-year="lobbyInfo?.year"
:current-month="lobbyInfo?.month"
:turn-term-minutes="lobbyInfo?.turnTerm"
@@ -528,7 +567,12 @@ watch(
<NationBasicCard :nation="nation" :loading="loading" />
</PanelCard>
<PanelCard title="장수 스탯" hide-header aria-label="장수 정보" data-main-target="general">
<GeneralBasicCard :general="general" :loading="loading" :nation-color="nation?.color" />
<GeneralInformationPanel
:general="generalPanel"
:summary="generalSummary"
:loading="loading"
:nation-color="nation?.color"
/>
</PanelCard>
<MainNationMenu
class="nation-menu-middle"
@@ -4,7 +4,9 @@ import { computed, onMounted, ref } from 'vue';
import { formatReservedCommandBrief } from '../components/command/reservedCommandBrief';
import type { CommandTable } from '../components/command/types';
import LegacySortControls from '../components/ui/LegacySortControls.vue';
import DirectoryTooltip from '../components/directory/DirectoryTooltip.vue';
import { getNpcColor } from '../utils/npcColor';
import { generalInjuryPresentation } from '../utils/generalInjury';
import { trpc } from '../utils/trpc';
type Result = Awaited<ReturnType<typeof trpc.nation.getSecretGeneralList.query>>;
type ReservedCommand = Result['generals'][number]['reservedCommands'][number];
@@ -48,6 +50,18 @@ const generals = computed(() =>
const closeWindow = () => window.close();
const displayName = (general: { name: string; npcState: number }) =>
general.npcState > 0 && !/^[ⓜⓝ㉥]/u.test(general.name) ? `${general.name}` : general.name;
const injuryInfo = (injury: number) => generalInjuryPresentation(injury);
const injuryDescription = (general: Result['generals'][number]): string =>
general.injury > 0 ? `부상 ${general.injury}% · ${injuryInfo(general.injury).text}` : '';
const statInjuryDescription = (
general: Result['generals'][number],
label: string,
original: number,
effective: number
): string =>
general.injury > 0
? `부상 ${general.injury}% · ${injuryInfo(general.injury).text} · 원래 ${label} ${original} → 적용 ${effective}`
: '';
const commandBrief = (command: ReservedCommand): string =>
formatReservedCommandBrief('general', command.action, command.args, commandTable.value);
const updateSelectedSort = (value: number): void => {
@@ -229,15 +243,72 @@ onMounted(load);
:data-npc-state="general.npcState"
>
<td>
<span data-general-name :style="{ color: getNpcColor(general.npcState) }">{{
displayName(general)
}}</span
<DirectoryTooltip
:title="`부상 · ${injuryInfo(general.injury).text}`"
:description="injuryDescription(general)"
:test-id="`secret-injury-name-${general.id}`"
>
<span
data-general-name
:style="{
color:
general.injury > 0
? injuryInfo(general.injury).color
: getNpcColor(general.npcState),
}"
>{{ displayName(general) }}</span
> </DirectoryTooltip
><br />Lv {{ general.experienceLevel }}
</td>
<td>
{{ general.stats.leadership
}}<span v-if="general.leadershipBonus" class="bonus">+{{ general.leadershipBonus }}</span
>{{ general.stats.strength }}{{ general.stats.intelligence }}
<DirectoryTooltip
title="통솔 부상"
:description="
statInjuryDescription(
general,
'통솔',
general.baseStats.leadership,
general.stats.leadership
)
"
:test-id="`secret-injury-leadership-${general.id}`"
>
<span :style="{ color: injuryInfo(general.injury).color }">{{
general.stats.leadership
}}</span
><span v-if="general.leadershipBonus" class="bonus"
>+{{ general.leadershipBonus }}</span
>
</DirectoryTooltip>
<DirectoryTooltip
title="무력 부상"
:description="
statInjuryDescription(
general,
'무력',
general.baseStats.strength,
general.stats.strength
)
"
:test-id="`secret-injury-strength-${general.id}`"
><span :style="{ color: injuryInfo(general.injury).color }">{{
general.stats.strength
}}</span></DirectoryTooltip
><DirectoryTooltip
title="지력 부상"
:description="
statInjuryDescription(
general,
'지력',
general.baseStats.intelligence,
general.stats.intelligence
)
"
:test-id="`secret-injury-intelligence-${general.id}`"
><span :style="{ color: injuryInfo(general.injury).color }">{{
general.stats.intelligence
}}</span></DirectoryTooltip
>
</td>
<td>{{ general.troopName ?? '-' }}</td>
<td>{{ general.gold }}</td>