From d0b9b8f211ac11513651a5a4bb67e9e06645e8e1 Mon Sep 17 00:00:00 2001 From: hided62 Date: Sat, 15 Aug 2026 18:17:59 +0000 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=EC=84=9C=EB=B2=84=20=EB=B3=B4?= =?UTF-8?q?=EC=A0=95=20=EC=8B=9C=EA=B0=81=EC=9D=84=20=EB=A1=9C=EC=BB=AC=20?= =?UTF-8?q?=EC=8B=9C=EA=B3=84=EB=A1=9C=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 명령 목록 중앙 시계는 서버 게임 시각과 클라이언트 시각 차이를 보정해 흐르게 한다. 장수 다음 턴과 예약 행 시각도 브라우저 로컬 시간대로 투영한다. --- app/game-frontend/e2e/mainNavigation.spec.ts | 39 +++++++++++---- .../src/components/main/CommandListPanel.vue | 48 ++++++++++++++++--- .../src/components/main/GeneralBasicCard.vue | 4 +- app/game-frontend/src/utils/legacyDateTime.ts | 8 ++++ app/game-frontend/src/views/MainView.vue | 4 ++ app/game-frontend/test/legacyDateTime.test.ts | 17 ++++++- 6 files changed, 100 insertions(+), 20 deletions(-) diff --git a/app/game-frontend/e2e/mainNavigation.spec.ts b/app/game-frontend/e2e/mainNavigation.spec.ts index 6100a9a6..c36fdc16 100644 --- a/app/game-frontend/e2e/mainNavigation.spec.ts +++ b/app/game-frontend/e2e/mainNavigation.spec.ts @@ -21,6 +21,8 @@ type NavigationFixture = { operations: string[]; generalName?: string; generalTurnTime?: string; + serverTime?: string; + clockMode?: 'realtime' | 'manual'; cityDefence?: number; cityState?: number; nationRate?: number; @@ -346,6 +348,8 @@ const installFixture = async (page: Page, state: NavigationFixture) => { year: state.currentYear ?? 185, month: state.currentMonth ?? 1, turnTerm: 10, + serverTime: state.serverTime ?? '2026-08-13T00:00:00.000Z', + clockMode: state.clockMode ?? 'realtime', scenarioTitle: state.scenarioTitle ?? '', }); } @@ -766,7 +770,7 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro await persistArtifact(page, `${basePath.slice(1)}-desktop-1200`); }); -test('main general card and command clock render the next turn with second precision', async ({ page }) => { +test('main general card uses local turn time and command clock tracks corrected server time', async ({ page }) => { const state: NavigationFixture = { officerLevel: 0, permission: 0, @@ -776,22 +780,29 @@ test('main general card and command clock render the next turn with second preci generalMeCalls: 0, operations: [], generalName: 'Administrator', - generalTurnTime: '2026-08-13T00:07:06.713Z', + generalTurnTime: '2026-08-13T00:09:10.713Z', + serverTime: '2026-08-13T00:07:06.250Z', + clockMode: 'realtime', currentYear: 179, currentMonth: 8, }; await installFixture(page, state); + await page.clock.install({ time: new Date('2026-08-13T00:00:00.000Z') }); + const cdp = await page.context().newCDPSession(page); + await cdp.send('Emulation.setTimezoneOverride', { timezoneId: 'Asia/Seoul' }); await page.setViewportSize({ width: 1200, height: 900 }); await waitForMain(page); const title = page.locator('[data-main-target="general"] .general-title').first(); await expect(title).toContainText('Administrator'); await expect(title).toContainText('용장'); - await expect(title).toContainText('09:07:06'); - await expect(title).not.toContainText('00:07'); + await expect(title).toContainText('09:09:10'); + await expect(title).not.toContainText('00:09'); const commandClock = page.locator('[data-main-target="commands"] [data-command-current-time]').first(); await expect(commandClock).toHaveText('09:07:06'); await expect(commandClock).not.toHaveText('00:07'); + await page.clock.runFor(1_000); + await expect(commandClock).toHaveText('09:07:07'); const generalCard = page.locator('[data-main-target="general"] [data-general-basic-card]').first(); await expect(generalCard).toContainText('수비 함(훈사80)'); await expect(generalCard).toContainText('5 턴'); @@ -836,9 +847,9 @@ test('main general card and command clock render the next turn with second preci const target = resolve(artifactRoot); await mkdir(target, { recursive: true }); await Promise.all([ - page.screenshot({ path: resolve(target, 'main-turn-time-seoul-desktop-1200.png'), fullPage: true }), + page.screenshot({ path: resolve(target, 'main-turn-time-local-desktop-1200.png'), fullPage: true }), writeFile( - resolve(target, 'main-turn-time-seoul-desktop-1200.json'), + resolve(target, 'main-turn-time-local-desktop-1200.json'), `${JSON.stringify({ title: desktopGeometry, commandClock: desktopClockGeometry }, null, 2)}\n` ), ]); @@ -846,9 +857,9 @@ test('main general card and command clock render the next turn with second preci await page.setViewportSize({ width: 500, height: 900 }); const mobileTitle = page.locator('[data-main-target="general"] .general-title').first(); - await expect(mobileTitle).toContainText('09:07:06'); + await expect(mobileTitle).toContainText('09:09:10'); const mobileCommandClock = page.locator('[data-main-target="commands"] [data-command-current-time]').first(); - await expect(mobileCommandClock).toHaveText('09:07:06'); + await expect(mobileCommandClock).toHaveText('09:07:07'); const mobileGeometry = { title: await mobileTitle.evaluate((element) => ({ width: element.getBoundingClientRect().width, @@ -874,15 +885,23 @@ test('main general card and command clock render the next turn with second preci if (artifactRoot) { await Promise.all([ page.screenshot({ - path: resolve(artifactRoot, 'main-turn-time-seoul-mobile-500.png'), + path: resolve(artifactRoot, 'main-turn-time-local-mobile-500.png'), fullPage: true, }), writeFile( - resolve(artifactRoot, 'main-turn-time-seoul-mobile-500.json'), + resolve(artifactRoot, 'main-turn-time-local-mobile-500.json'), `${JSON.stringify(mobileGeometry, null, 2)}\n` ), ]); } + + state.clockMode = 'manual'; + state.serverTime = '2026-08-13T00:08:30.000Z'; + await page.reload(); + const frozenClock = page.locator('[data-main-target="commands"] [data-command-current-time]').first(); + await expect(frozenClock).toHaveText('09:08:30'); + await page.clock.runFor(2_000); + await expect(frozenClock).toHaveText('09:08:30'); }); test('pure NPC message senders are not rendered as reply targets', async ({ page }) => { diff --git a/app/game-frontend/src/components/main/CommandListPanel.vue b/app/game-frontend/src/components/main/CommandListPanel.vue index 86ae7745..0a2d2124 100644 --- a/app/game-frontend/src/components/main/CommandListPanel.vue +++ b/app/game-frontend/src/components/main/CommandListPanel.vue @@ -1,8 +1,8 @@