路由修正

This commit is contained in:
马梓彭 2026-09-09 14:25:44 +08:00
parent 2521a0f7f8
commit a6f520a787
4 changed files with 30 additions and 5 deletions

View File

@ -40,10 +40,12 @@ const checks = [
['SQL状态30为已投屏', sql, "WHEN 30 THEN N''已投屏''"],
['报名与秩序册数据源', launcher, "switchSource('orderbook')"],
['赛事列表分页', launcher, 'v-model:current-page="pageNo"'],
['工作台保存赛事上下文', launcher, "sessionStorage.setItem('scoring-context'"],
['启动页统一保存赛事上下文', launcher, 'saveScoringContext({eventId:Number(event.id)'],
['秩序册具有独立页面', orderBookPage, 'orderBookImportPost'],
['秩序册自动解析已选赛事', orderBookPage, 'resolveScoringEvent(route.query)'],
['成绩管理与投屏使用独立菜单路由', menuSeed, '"Path": "/scoring/cast"'],
['秩序册直达路由具有兼容兜底', backEndRoutes, 'ensureScoringOperationalRoutes'],
['旧秩序册菜单路由自动修正', backEndRoutes, 'normalizeScoringMenuRoutes(routeList)'],
['超级管理员具有秩序册菜单授权', roleMenuSeed, '"MenuId": 1088'],
['工作台动态评分列', workbench, 'v-for="col in detailColumns"'],
['规定赛隐藏难度', scoreScreen, "includes('PRESCRIBED')"],

View File

@ -103,7 +103,10 @@ export async function initBackEndControlRoutes() {
];
// 工作台业务页需要携带赛事上下文,不能依赖菜单接口是否已经下发全部子菜单。
// 这些路由只作为隐藏的运行路由注册,左侧菜单仍以后端权限菜单为准。
const routesWithScoringFallback = ensureScoringOperationalRoutes(routeList);
// 兼容已部署数据库里的旧菜单数据:旧版“秩序册”曾错误复用 launcher 路由。
// 前端按稳定的路由名称/菜单编码修正运行地址,避免用户必须等待菜单种子重新入库。
const normalizedRouteList = normalizeScoringMenuRoutes(routeList);
const routesWithScoringFallback = ensureScoringOperationalRoutes(normalizedRouteList);
dynamicRoutes[0].children = await backEndComponent([...routesWithScoringFallback, ...staticRoute]);
// dynamicRoutes[0].children = await backEndComponent(routeList);
// 添加动态路由
@ -166,6 +169,24 @@ export function getBackEndControlRoutes() {
return SysMenuApi.getMenus();
}
function normalizeScoringMenuRoutes(routes: any[]) {
return routes.map((item) => {
const children = item?.children?.length ? normalizeScoringMenuRoutes(item.children) : item?.children;
const routeName = String(item?.name || item?.routeName || '');
const menuCode = String(item?.code || item?.meta?.code || '');
const title = String(item?.meta?.title || '');
const isScoringOrderBookTitle = title === '秩序册' && String(item?.path || '').startsWith('/scoring/');
const isOrderBook = routeName === 'scoringOrderBook' || menuCode === 'scoring:orderbook' || isScoringOrderBookTitle;
if (!isOrderBook) return children === item?.children ? item : { ...item, children };
return {
...item,
path: '/scoring/orderbook',
component: 'scoring/orderbook/index',
children,
};
});
}
function ensureScoringOperationalRoutes(routes: any[]) {
const paths = new Set<string>();
const collectPaths = (items: any[]) => items.forEach((item) => {

View File

@ -25,6 +25,7 @@
import { ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { workbenchEventsGet } from '/@/api/match/workbench';
import { saveScoringContext } from '/@/utils/scoringContext';
const route=useRoute(), router=useRouter(), step=ref('mode'), sourceMode=ref('registration'), keyword=ref(''), events=ref([]), loading=ref(false), pageNo=ref(1), total=ref(0);
const pageSize=8;
@ -35,7 +36,7 @@ if(route.query.sourceMode||route.query.eventId){sessionStorage.setItem('scoring-
function switchSource(value){sourceMode.value=value;pageNo.value=1;loadEvents()}
function searchEvents(){pageNo.value=1;loadEvents()}
async function loadEvents(){loading.value=true;try{const res=await workbenchEventsGet({pageNo:pageNo.value,pageSize,eventName:keyword.value||undefined,sourceMode:sourceMode.value});const page=res?.data||{};events.value=page.rows||page.list||page.items||[];total.value=Number(page.total||page.totalCount||events.value.length)}finally{loading.value=false}}
function enterEvent(event){const context={eventId:Number(event.id),eventName:event.eventName,mode:'freestyle',sourceMode:sourceMode.value};sessionStorage.setItem('scoring-context',JSON.stringify(context));const path=sourceMode.value==='orderbook'?'/scoring/orderbook':'/scoring/workbench';router.push({path,query:{eventId:context.eventId,eventName:context.eventName}})}
function enterEvent(event){const context=saveScoringContext({eventId:Number(event.id),eventName:event.eventName,mode:'freestyle',sourceMode:sourceMode.value});const path=sourceMode.value==='orderbook'?'/scoring/orderbook':'/scoring/workbench';router.push({path,query:{eventId:context.eventId,eventName:context.eventName}})}
function dateRange(event){const start=String(event.matchStartTime||'').slice(0,10),end=String(event.matchEndTime||'').slice(0,10);return start||end?`${start||'待定'} 至 ${end||'待定'}`:'比赛时间待定'}
function eventStatusName(status){return({0:'未开始',1:'报名中',2:'报名结束',3:'比赛中',4:'已结束'})[status]||'待处理'}
function eventStatusType(status){return({1:'warning',2:'info',3:'success',4:'info'})[status]||''}

View File

@ -19,10 +19,11 @@ import { ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { orderBookTemplateGet, orderBookImportPost, orderBookConfirmPost } from '/@/api/match/workbench';
import { resolveScoringEvent } from '/@/utils/scoringContext';
const route=useRoute(),router=useRouter();
let saved={};try{saved=JSON.parse(sessionStorage.getItem('scoring-context')||'{}')}catch{saved={}}
const eventId=Number(route.query.eventId)||Number(saved.eventId)||0,eventName=String(route.query.eventName||saved.eventName||'未选择赛事');
const scoringEvent=resolveScoringEvent(route.query);
const eventId=scoringEvent.eventId,eventName=scoringEvent.eventName;
const file=ref(null),result=ref(null),parsing=ref(false),confirming=ref(false);
if(!eventId)router.replace({path:'/scoring/launcher',query:{sourceMode:'orderbook'}});
function changeEvent(){router.push({path:'/scoring/launcher',query:{sourceMode:'orderbook'}})}