From 6f47849e1e1570a337ba71c57760009c31516f1d Mon Sep 17 00:00:00 2001 From: AskaEth Date: Thu, 10 Sep 2026 10:20:03 +0800 Subject: [PATCH] =?UTF-8?q?fix(display):=20=E9=9A=90=E8=97=8F=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E6=A0=87=E8=AF=86=20+=20=E7=A7=AF=E5=88=86=E6=A6=9C?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8D=95=E4=BD=8D=20logo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TopBar 的「实例 N · 屏 N」只在该窗口确实处于调试态时渲染:非 windowed(kiosk)不显示, 窗口化下按 F11 全屏也不显示(同时监听 fullscreenchange,与 App.vue 口径一致) - 积分榜与团体奖牌榜的队名左侧渲染单位 logo:数据本来就下发了(dto/standings.go 的 LogoPath),只是页面没画。图标 1em 随行字号浮动、object-fit:contain,行高不会被撑开; 无 logo 不占位,加载失败 visibility:hidden 保留占位避免队名跳动,@load 会复原 - resolveAssetUrl(路径归一化)从 admin 目录收敛到 web/src/shared/asset.ts, 管理端与大屏共用一份;原 image-path 测试随之迁到 shared/tests 未做(需服务端 DTO 支持,本次未授权):分项成绩页与个人榜的单位列同样没有 logoPath 字段, 所以那两个页面仍无法显示单位 logo。 自检:vue-tsc + pnpm build 通过;前端 node --test 69/69。 --- .../components/system/ImageUploadField.vue | 2 +- web/src/display/components/TopBar.vue | 12 +++++++ .../components/pages/StandingsPage.vue | 34 +++++++++++++++++-- .../components/pages/TeamMedalsPage.vue | 33 +++++++++++++++++- .../system/imagePath.ts => shared/asset.ts} | 0 web/src/shared/index.ts | 1 + .../tests/asset.test.ts} | 2 +- 7 files changed, 79 insertions(+), 5 deletions(-) rename web/src/{admin/components/system/imagePath.ts => shared/asset.ts} (100%) rename web/src/{admin/tests/image-path.test.ts => shared/tests/asset.test.ts} (94%) diff --git a/web/src/admin/components/system/ImageUploadField.vue b/web/src/admin/components/system/ImageUploadField.vue index 43c885c..65b5180 100644 --- a/web/src/admin/components/system/ImageUploadField.vue +++ b/web/src/admin/components/system/ImageUploadField.vue @@ -3,8 +3,8 @@ import { computed, onBeforeUnmount, ref, watch } from 'vue' import MxIcon from '../MxIcon.vue' import { adminApi } from '../../api/client' import { useToastStore } from '../../stores/toast' +import { resolveAssetUrl } from '@/shared' import { describeError } from './systemApi' -import { resolveAssetUrl } from './imagePath' /** * 图片字段:文本框(可手填 / 粘贴路径)+ 上传按钮 + 缩略图预览。 diff --git a/web/src/display/components/TopBar.vue b/web/src/display/components/TopBar.vue index 4f079fd..16eb28a 100644 --- a/web/src/display/components/TopBar.vue +++ b/web/src/display/components/TopBar.vue @@ -2,6 +2,7 @@ import { computed, onUnmounted, ref } from 'vue' import { formatClock } from '@/shared' import { useScoreboard } from '../useScoreboard' +import { isWindowed } from '../windowed' import OfflineBadge from './OfflineBadge.vue' const { settings, options } = useScoreboard() @@ -19,7 +20,18 @@ const subtitle = computed(() => display.value?.subtitle?.trim() ?? '') const host = computed(() => settings.value?.event.host?.trim() || '主办方待配置') const logo = computed(() => display.value?.logo?.trim() || '') const clock = computed(() => formatClock(now.value)) +// 单屏窗口化时用来分辨「这块屏是哪个实例」;现场展示(kiosk,或窗口化后按 F11 全屏)都不该出现。 +// 监听在 setup 阶段就挂上,onUnmounted 里摘掉,不引入额外 import。 +const fullscreen = ref(document.fullscreenElement !== null) +function onFullscreenChange(): void { + fullscreen.value = document.fullscreenElement !== null +} +document.addEventListener('fullscreenchange', onFullscreenChange) +onUnmounted(() => document.removeEventListener('fullscreenchange', onFullscreenChange)) + +// 实例/屏号都缺失时返回空串,模板的 v-if 顺带挡掉空元素。 const identity = computed(() => { + if (!isWindowed() || fullscreen.value) return '' const parts: string[] = [] if (options.value.instance !== null) parts.push(`实例 ${options.value.instance}`) if (options.value.screen !== null) parts.push(`屏 ${options.value.screen}`) diff --git a/web/src/display/components/pages/StandingsPage.vue b/web/src/display/components/pages/StandingsPage.vue index 0b22418..7e5305d 100644 --- a/web/src/display/components/pages/StandingsPage.vue +++ b/web/src/display/components/pages/StandingsPage.vue @@ -1,6 +1,6 @@