fix(game-ui): 암행부 예약 명령 요약을 복원

암행부 API가 앞 5턴의 action과 args를 함께 반환하도록 수정한다.\n개인턴·사령부 공용 formatter를 암행부와 세력도시 연동 표에 적용하고 Chromium 회귀를 추가한다.
This commit is contained in:
2026-08-21 02:48:44 +00:00
parent 4eb80c2970
commit 89f2c6a176
6 changed files with 173 additions and 17 deletions
@@ -2,6 +2,8 @@
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { formatReservedCommandBrief } from '../components/command/reservedCommandBrief';
import type { CommandTable } from '../components/command/types';
import { useGameFeedback } from '../composables/useGameFeedback';
import { getNpcColor } from '../utils/npcColor';
import { legacyNationTextColor } from '../utils/legacyNationColor';
@@ -13,10 +15,12 @@ type SecretResult = Awaited<ReturnType<typeof trpc.nation.getSecretGeneralList.q
type PersonnelResult = Awaited<ReturnType<typeof trpc.nation.getPersonnelInfo.query>>;
type City = Result['cities'][number];
type SecretGeneral = SecretResult['generals'][number];
type ReservedCommand = SecretGeneral['reservedCommands'][number];
type OfficerLevel = 2 | 3 | 4;
type Sort = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
const data = ref<Result | null>(null);
const secretData = ref<SecretResult | null>(null);
const commandTable = ref<CommandTable | null>(null);
const personnelData = ref<PersonnelResult | null>(null);
const error = ref('');
const integrationError = ref('');
@@ -148,6 +152,8 @@ const commandNeedsAttention = (city: City, command: string): boolean => {
if (normalized.includes('성벽보수')) return city.wall - city.wallMax > -700;
return false;
};
const commandBrief = (command: ReservedCommand): string =>
formatReservedCommandBrief('general', command.action, command.args, commandTable.value);
const loadSecretIntegration = async (): Promise<void> => {
if (secretLoading.value) {
@@ -161,7 +167,10 @@ const loadSecretIntegration = async (): Promise<void> => {
secretLoading.value = true;
integrationError.value = '';
try {
secretData.value = await trpc.nation.getSecretGeneralList.query();
const secret = await trpc.nation.getSecretGeneralList.query();
const table = await trpc.turns.getCommandTable.query({ generalId: secret.viewer.generalId });
secretData.value = secret;
commandTable.value = table;
} catch (cause) {
integrationError.value = cause instanceof Error ? cause.message : '암행부 연동에 실패했습니다.';
showErrorToast(integrationError.value);
@@ -496,13 +505,17 @@ onMounted(async () => {
<div
v-for="(command, commandIndex) in general.reservedCommands"
:key="commandIndex"
:title="commandBrief(command)"
>
{{ commandIndex + 1 }} :
<span
:class="{
'command-attention': commandNeedsAttention(city, command),
'command-attention': commandNeedsAttention(
city,
commandBrief(command)
),
}"
>{{ command }}</span
>{{ commandBrief(command) }}</span
>
</div>
</template>
@@ -1,10 +1,14 @@
<script setup lang="ts">
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
import { computed, onMounted, ref } from 'vue';
import { formatReservedCommandBrief } from '../components/command/reservedCommandBrief';
import type { CommandTable } from '../components/command/types';
import { trpc } from '../utils/trpc';
type Result = Awaited<ReturnType<typeof trpc.nation.getSecretGeneralList.query>>;
type ReservedCommand = Result['generals'][number]['reservedCommands'][number];
type Sort = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
const data = ref<Result | null>(null);
const commandTable = ref<CommandTable | null>(null);
const error = ref('');
const loading = ref(false);
const sort = ref<Sort>(7);
@@ -13,7 +17,10 @@ const load = async () => {
loading.value = true;
error.value = '';
try {
data.value = await trpc.nation.getSecretGeneralList.query();
const result = await trpc.nation.getSecretGeneralList.query();
const table = await trpc.turns.getCommandTable.query({ generalId: result.viewer.generalId });
data.value = result;
commandTable.value = table;
} catch (cause) {
error.value = cause instanceof Error ? cause.message : '암행부를 불러오지 못했습니다.';
} finally {
@@ -35,6 +42,8 @@ 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 commandBrief = (command: ReservedCommand): string =>
formatReservedCommandBrief('general', command.action, command.args, commandTable.value);
onMounted(load);
</script>
@@ -142,8 +151,12 @@ onMounted(load);
<td class="turns">
<template v-if="general.npcState >= 2">NPC 장수</template
><template v-else
><div v-for="(command, index) in general.reservedCommands" :key="index">
{{ index + 1 }} : {{ command }}
><div
v-for="(command, index) in general.reservedCommands"
:key="index"
:title="commandBrief(command)"
>
{{ index + 1 }} : {{ commandBrief(command) }}
</div></template
>
</td>