diff --git a/src/router/backEnd.ts b/src/router/backEnd.ts index eaa1de9..2074d80 100644 --- a/src/router/backEnd.ts +++ b/src/router/backEnd.ts @@ -175,8 +175,19 @@ function normalizeScoringMenuRoutes(routes: any[]) { const routeName = String(item?.name || item?.routeName || ''); const menuCode = String(item?.code || item?.meta?.code || ''); const title = String(item?.meta?.title || ''); + const path = String(item?.path || ''); const isScoringOrderBookTitle = title === '秩序册' && String(item?.path || '').startsWith('/scoring/'); const isOrderBook = routeName === 'scoringOrderBook' || menuCode === 'scoring:orderbook' || isScoringOrderBookTitle; + const isScoringCastTitle = title === '成绩投屏' && path.startsWith('/scoring/'); + const isScoringCast = routeName === 'scoringCast' || menuCode === 'scoring:cast' || path === '/scoring/cast' || isScoringCastTitle; + if (isScoringCast) { + return { + ...item, + path: '/scoring/cast', + component: 'scoring/screen/index', + children, + }; + } if (!isOrderBook) return children === item?.children ? item : { ...item, children }; return { ...item, @@ -201,7 +212,7 @@ function ensureScoringOperationalRoutes(routes: any[]) { { path: '/scoring/launcher', name: 'scoringLauncherFallback', component: 'scoring/launcher/index', meta: { title: '工作台', isKeepAlive: true } }, { path: '/scoring/orderbook', name: 'scoringOrderBookFallback', component: 'scoring/orderbook/index', meta: { title: '秩序册', isHide: true, isKeepAlive: true } }, { path: '/scoring/workbench', name: 'scoringWorkbenchFallback', component: 'scoring/workbench/index', meta: { title: '成绩管理', isHide: true, isKeepAlive: true } }, - { path: '/scoring/cast', name: 'scoringCastFallback', component: 'scoring/workbench/index', meta: { title: '成绩投屏', isHide: true, isKeepAlive: true } }, + { path: '/scoring/cast', name: 'scoringCastFallback', component: 'scoring/screen/index', meta: { title: '成绩投屏', isHide: true, isKeepAlive: true } }, ].filter((item) => !paths.has(item.path)); return [...routes, ...fallbacks]; } diff --git a/src/router/route.ts b/src/router/route.ts index 523a35f..8cd34fd 100644 --- a/src/router/route.ts +++ b/src/router/route.ts @@ -602,10 +602,19 @@ export const staticRoutes: Array = [ title: '登录', }, }, + { + path: '/scoring/cast', + name: 'scoringCast', + component: () => import('/@/views/scoring/cast/index.vue'), + meta: { + title: '赛事大屏', + isPublic: true, + }, + }, { path: '/scoring/screen', name: 'scoringScreen', - component: () => import('/@/views/scoring/screen/index.vue'), + redirect: (to) => ({ path: '/scoring/cast', query: { ...to.query, castMode: 'score' } }), meta: { title: '成绩大屏', isPublic: true, @@ -614,7 +623,7 @@ export const staticRoutes: Array = [ { path: '/scoring/checkin-screen', name: 'scoringCheckinScreen', - component: () => import('/@/views/scoring/checkin-screen/index.vue'), + redirect: (to) => ({ path: '/scoring/cast', query: { ...to.query, castMode: 'checkin' } }), meta: { title: '检录进度大屏', isPublic: true, diff --git a/src/views/scoring/cast/index.vue b/src/views/scoring/cast/index.vue new file mode 100644 index 0000000..74cf8d5 --- /dev/null +++ b/src/views/scoring/cast/index.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/views/scoring/checkin-screen/index.vue b/src/views/scoring/checkin-screen/index.vue index 2755bb9..9699736 100644 --- a/src/views/scoring/checkin-screen/index.vue +++ b/src/views/scoring/checkin-screen/index.vue @@ -43,13 +43,15 @@ import { computed, onBeforeUnmount, onMounted, ref } from 'vue'; import { useRoute } from 'vue-router'; import { checkinScreenCastGet } from '/@/api/match/workbench'; -const route=useRoute(), eventId=Number(route.query.eventId)||0; +const route=useRoute(); +let savedContext={};try{savedContext=JSON.parse(sessionStorage.getItem('scoring-context')||'{}')}catch{savedContext={}} +const eventId=Number(route.query.eventId)||Number(savedContext.eventId)||0; const data=ref({stages:[],units:[]}), offline=ref(false), clock=ref(''), week=ref(''), fullscreen=ref(false), controlsVisible=ref(true); let pollTimer,clockTimer,controlTimer,unitPage=ref(0),unitTimer,serverBaseMs=Date.now(),syncedAtMs=Date.now(),requesting=false; const stages=computed(()=>data.value.stages||[]),currentCheckin=computed(()=>data.value.currentCheckin),currentCompeting=computed(()=>data.value.currentCompeting); const visibleUnits=computed(()=>{const all=data.value.units||[];const pages=Math.max(1,Math.ceil(all.length/7));const page=unitPage.value%pages;return all.slice(page*7,page*7+7)}); const currentClockDate=()=>new Date(serverBaseMs+(Date.now()-syncedAtMs)); -async function load(){if(!eventId||requesting)return;requesting=true;try{const res=await checkinScreenCastGet({eventId});data.value=res?.data||{stages:[],units:[]};offline.value=false;syncClock()}catch{offline.value=true}finally{requesting=false}} +async function load(){if(!eventId||requesting)return;requesting=true;try{const res=await checkinScreenCastGet({eventId,_t:Date.now()});const body=res?.data??res;data.value=body?.data??body??{stages:[],units:[]};offline.value=false;syncClock()}catch{offline.value=true}finally{requesting=false}} function syncClock(){const raw=data.value.serverTime||data.value.serverTimeText;const parsed=raw?new Date(String(raw).replace(' ','T')):new Date();serverBaseMs=Number.isNaN(parsed.getTime())?Date.now():parsed.getTime();syncedAtMs=Date.now();tick()} function tick(){const now=currentClockDate();clock.value=formatDate(now);week.value=['星期日','星期一','星期二','星期三','星期四','星期五','星期六'][now.getDay()]} function formatDate(d){const p=n=>String(n).padStart(2,'0');return `${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`} diff --git a/src/views/scoring/orderbook/index.vue b/src/views/scoring/orderbook/index.vue index d0bd513..63057e9 100644 --- a/src/views/scoring/orderbook/index.vue +++ b/src/views/scoring/orderbook/index.vue @@ -15,22 +15,24 @@ diff --git a/src/views/scoring/screen/index.vue b/src/views/scoring/screen/index.vue index dea9308..86d4e7d 100644 --- a/src/views/scoring/screen/index.vue +++ b/src/views/scoring/screen/index.vue @@ -1,7 +1,7 @@