From 23491877c1047752a966dfd22f20b5fca8045739 Mon Sep 17 00:00:00 2001 From: hided62 Date: Mon, 17 Aug 2026 10:28:36 +0000 Subject: [PATCH] =?UTF-8?q?fix(game-ui):=20=EA=B0=90=EC=B0=B0=EB=B6=80=20?= =?UTF-8?q?=EA=B8=B0=EB=A1=9D=20=EB=B0=B0=EA=B2=BD=EA=B3=BC=20=EB=AA=A8?= =?UTF-8?q?=EB=B0=94=EC=9D=BC=20=ED=91=9C=EC=8B=9C=EB=A5=BC=20=EB=B0=94?= =?UTF-8?q?=EB=A1=9C=EC=9E=A1=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 중복 하단 메타를 제거하고 최근 전투를 연도 없는 독립 행으로 넓힌다. 기록 본문에 walnut 질감을 적용하고 고정 높이 잘림을 없애 모바일 전투 결과까지 표시한다. production Chromium 검증이 실제 로그 유형과 배경·기하를 확인하도록 감찰부 fixture와 assertion도 보강한다. --- app/game-frontend/e2e/inGameMenus.spec.ts | 83 ++++++++++++++++--- .../src/views/BattleCenterView.vue | 47 +++++------ 2 files changed, 95 insertions(+), 35 deletions(-) diff --git a/app/game-frontend/e2e/inGameMenus.spec.ts b/app/game-frontend/e2e/inGameMenus.spec.ts index 05503f87..a7c616b8 100644 --- a/app/game-frontend/e2e/inGameMenus.spec.ts +++ b/app/game-frontend/e2e/inGameMenus.spec.ts @@ -327,9 +327,27 @@ const install = async (page: Page, state: FixtureState) => { const rawRequestBody: unknown = route.request().postData() ? route.request().postDataJSON() : {}; const requestBody = rawRequestBody && typeof rawRequestBody === 'object' ? (rawRequestBody as Record) : {}; + const queryInputText = new URL(route.request().url()).searchParams.get('input'); + let queryInput: Record = {}; + if (queryInputText) { + try { + const parsed: unknown = JSON.parse(queryInputText); + if (parsed && typeof parsed === 'object') { + queryInput = parsed as Record; + } + } catch { + queryInput = {}; + } + } const results = operations.map((operation, operationIndex) => { const rawPayload = - requestBody[String(operationIndex)] ?? (operations.length === 1 ? requestBody : undefined); + requestBody[String(operationIndex)] ?? + queryInput[String(operationIndex)] ?? + (operations.length === 1 + ? Object.keys(requestBody).length > 0 + ? requestBody + : queryInput + : undefined); const payload = rawPayload && typeof rawPayload === 'object' ? (rawPayload as TrpcRequestPayload) : undefined; const jsonInput = @@ -537,10 +555,12 @@ const install = async (page: Page, state: FixtureState) => { return response(battleCenter(state)); } if (operation === 'nation.getGeneralLog') { - const type = new URL(route.request().url()).searchParams.get('input')?.includes('generalAction') - ? 'generalAction' - : operation; - return response({ type, generalId: 7, logs: [{ id: 1, text: '감찰 기록' }] }); + const type = + typeof jsonInput.type === 'string' && + ['generalHistory', 'battleDetail', 'battleResult', 'generalAction'].includes(jsonInput.type) + ? jsonInput.type + : 'generalAction'; + return response({ type, generalId: 7, logs: [{ id: 1, text: `${type} 감찰 기록` }] }); } return response({ ok: true }); }); @@ -1310,7 +1330,9 @@ test('감찰부 keeps the selector interaction and shows the permission error pa await expect(page.locator('.selector-row select').nth(1)).toHaveValue('8'); await page.getByRole('button', { name: '다음 ▶' }).click(); await expect(page.locator('.selector-row select').nth(1)).toHaveValue('7'); - await expect(page.locator('.battle-general-name')).toContainText('검증장수 【 간의대부 | 건강 】'); + await expect(page.locator('.battle-general-name')).toContainText('검증장수'); + await expect(page.locator('.battle-general-name')).toContainText('간의대부'); + await expect(page.locator('.battle-general-name')).toContainText('건강'); await expect(page.locator('.battle-general-extra')).toContainText('계급29품관'); await expect(page.locator('.battle-general-card')).toContainText('병종보병'); await expect(page.locator('.battle-general-card')).not.toContainText('che_'); @@ -1321,6 +1343,11 @@ test('감찰부 keeps the selector interaction and shows the permission error pa expect(battleImages[1]?.backgroundImage).toContain('/game/crewtype1.png'); await expect(page.locator('.battle-general-card [role="progressbar"]')).toHaveCount(14); await expect(page.locator('.battle-general-card [aria-label*="1,275,975 (EX+)"]')).toHaveCount(5); + await expect(page.locator('.general-meta')).toHaveCount(0); + await expect(page.locator('.battle-general-extra__recent-value')).toHaveText('01-01 00:00'); + await expect(page.locator('.battle-general-extra__recent-value')).not.toContainText('2026'); + await expect(page.locator('.log-block')).toHaveCount(4); + await expect(page.locator('.log-block[data-log-type="battleResult"]')).toContainText('battleResult 감찰 기록'); expect( await page .locator('.battle-general-card [role="progressbar"]') @@ -1330,7 +1357,11 @@ test('감찰부 keeps the selector interaction and shows the permission error pa const geometry = await page.locator('.battle-page').evaluate((element) => { const selector = element.querySelector('.selector-row')!; const controls = [...selector.children].map((child) => (child as HTMLElement).getBoundingClientRect()); - const logBlock = element.querySelector('.log-block')!.getBoundingClientRect(); + const logBlocks = [...element.querySelectorAll('.log-block')]; + const logBlock = logBlocks[0]!.getBoundingClientRect(); + const recentLabel = element.querySelector('.battle-general-extra__recent-label')!; + const recentValue = element.querySelector('.battle-general-extra__recent-value')!; + const previousStat = recentLabel.previousElementSibling as HTMLElement; return { width: element.getBoundingClientRect().width, fontSize: getComputedStyle(element).fontSize, @@ -1341,6 +1372,11 @@ test('감찰부 keeps the selector interaction and shows the permission error pa backgroundImage: getComputedStyle(element).backgroundImage, generalBackgroundImage: getComputedStyle(element.querySelector('.battle-general-card')!) .backgroundImage, + logBackgroundImages: logBlocks.map((block) => getComputedStyle(block).backgroundImage), + recentLabelTop: recentLabel.getBoundingClientRect().top, + recentValueTop: recentValue.getBoundingClientRect().top, + recentValueWidth: recentValue.getBoundingClientRect().width, + previousStatTop: previousStat.getBoundingClientRect().top, }; }); expect(geometry.width).toBe(1000); @@ -1352,16 +1388,41 @@ test('감찰부 keeps the selector interaction and shows the permission error pa expect(geometry.logBlockWidth).toBeCloseTo(500, 0); expect(geometry.backgroundImage).toContain('back_walnut.jpg'); expect(geometry.generalBackgroundImage).toContain('back_blue.jpg'); + expect(geometry.logBackgroundImages).toHaveLength(4); + expect(geometry.logBackgroundImages.every((background) => background.includes('back_walnut.jpg'))).toBe(true); + expect(geometry.recentLabelTop).toBeCloseTo(geometry.recentValueTop, 0); + expect(geometry.recentLabelTop).toBeGreaterThan(geometry.previousStatTop); + expect(geometry.recentValueWidth).toBeGreaterThan(400); await persistParityArtifact(page, 'core-battle-center-desktop', geometry); await page.setViewportSize({ width: 500, height: 900 }); - const mobileGeometry = await page.locator('.selector-row').evaluate((element) => ({ - columns: getComputedStyle(element).gridTemplateColumns, - controlWidths: [...element.children].map((child) => (child as HTMLElement).getBoundingClientRect().width), - })); + const mobileGeometry = await page.locator('.battle-page').evaluate((element) => { + const selector = element.querySelector('.selector-row')!; + const battleResult = element.querySelector('.log-block[data-log-type="battleResult"]')!; + const footer = element.querySelector('.battle-footer')!; + const pageRect = element.getBoundingClientRect(); + const resultRect = battleResult.getBoundingClientRect(); + const footerRect = footer.getBoundingClientRect(); + return { + columns: getComputedStyle(selector).gridTemplateColumns, + controlWidths: [...selector.children].map((child) => (child as HTMLElement).getBoundingClientRect().width), + pageHeight: pageRect.height, + pageOverflow: getComputedStyle(element).overflow, + resultBottomWithinPage: resultRect.bottom <= pageRect.bottom, + footerAfterResult: footerRect.top >= resultRect.bottom, + resultBackgroundImage: getComputedStyle(battleResult).backgroundImage, + }; + }); expect(mobileGeometry.columns.split(' ')).toHaveLength(4); expect(mobileGeometry.controlWidths[0]).toBeCloseTo(83.33, 0); expect(mobileGeometry.controlWidths[1]).toBeCloseTo(125, 0); + expect(mobileGeometry.pageHeight).toBeGreaterThan(0); + expect(mobileGeometry.pageOverflow).toBe('visible'); + expect(mobileGeometry.resultBottomWithinPage).toBe(true); + expect(mobileGeometry.footerAfterResult).toBe(true); + expect(mobileGeometry.resultBackgroundImage).toContain('back_walnut.jpg'); + await page.locator('.log-block[data-log-type="battleResult"]').scrollIntoViewIfNeeded(); + await expect(page.locator('.log-block[data-log-type="battleResult"]')).toBeInViewport(); await persistParityArtifact(page, 'core-battle-center-mobile', mobileGeometry); await page.unrouteAll({ behavior: 'wait' }); diff --git a/app/game-frontend/src/views/BattleCenterView.vue b/app/game-frontend/src/views/BattleCenterView.vue index e2067bfa..759b5101 100644 --- a/app/game-frontend/src/views/BattleCenterView.vue +++ b/app/game-frontend/src/views/BattleCenterView.vue @@ -286,28 +286,26 @@ onMounted(() => { >{{ selectedGeneral.battleStats.killCrew.toLocaleString('ko-KR') }} 피살{{ selectedGeneral.battleStats.deathCrew.toLocaleString('ko-KR') }} - 최근 전투{{ selectedGeneral.recentWar || '-' }} + 최근 전투 + + {{ + formatServerDateTime(selectedGeneral.recentWar, { + format: 'monthDayTime', + fallback: '-', + }) + }} + -
-
- 최근 턴: - {{ - formatServerDateTime(selectedGeneral.turnTime, { format: 'hourMinute', fallback: '-' }) - }} -
-
최근 전투: {{ selectedGeneral.recentWar || '-' }}
-
전투 횟수: {{ selectedGeneral.warnum }}
-
-
+
{{ logLabels[type] }}