feat(web): 配置中心聚合页、路由迁移与权限页 key 同步
将原十余个独立配置页聚合为 调度策略/设备与库位/业务与集成/运维与回放/系统与权限 等聚合页 (Tab 与 URL ?tab= 同步),旧路径以 redirect 兼容深链接;AppShell 菜单与 mock/rbac 的页面 key 同步后端 PageCatalog;Dashboard 快捷入口改指聚合页对应 tab;新增 TaskTemplateView 取代并删除 MissionEditorView / OrchestrationView。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -154,26 +154,18 @@ const ADMIN_MENU: MenuItem[] = [
|
|||||||
{ path: '/admin/cars', label: '车辆管理', key: 'admin-cars' },
|
{ path: '/admin/cars', label: '车辆管理', key: 'admin-cars' },
|
||||||
{ path: '/admin/processes', label: '进程管理', key: 'admin-processes' },
|
{ path: '/admin/processes', label: '进程管理', key: 'admin-processes' },
|
||||||
{ path: '/admin/scripts', label: '脚本管理', key: 'admin-scripts' },
|
{ path: '/admin/scripts', label: '脚本管理', key: 'admin-scripts' },
|
||||||
{ path: '/admin/missions', label: '任务编排', key: 'admin-missions' }
|
{ path: '/admin/task-templates', label: '任务编排', key: 'admin-task-templates' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ path: '/admin/playback', label: '调度回放', icon: Notebook, key: 'admin-playback' },
|
|
||||||
{
|
{
|
||||||
path: '/admin/config', label: '平台配置中心', icon: Setting,
|
path: '/admin/config', label: '平台配置中心', icon: Setting,
|
||||||
children: [
|
children: [
|
||||||
{ path: '/admin/config/system', label: '系统级配置', key: 'admin-config-system' },
|
{ path: '/admin/config/strategy', label: '调度策略', key: 'admin-config-strategy' },
|
||||||
{ path: '/admin/config/integrations', label: '外部系统对接', key: 'admin-config-integrations' },
|
|
||||||
{ path: '/admin/config/routing', label: '路径规划', key: 'admin-config-routing' },
|
|
||||||
{ path: '/admin/config/vehicle-hub', label: '车辆运维', key: 'admin-vehicle-hub' },
|
{ path: '/admin/config/vehicle-hub', label: '车辆运维', key: 'admin-vehicle-hub' },
|
||||||
{ path: '/admin/config/charge', label: '充电策略', key: 'admin-config-charge' },
|
{ path: '/admin/config/facility', label: '设备与库位', key: 'admin-config-facility' },
|
||||||
{ path: '/admin/config/task', label: '任务分配', key: 'admin-config-task' },
|
{ path: '/admin/config/business', label: '业务与集成', key: 'admin-config-business' },
|
||||||
{ path: '/admin/config/traffic', label: '交通管制', key: 'admin-config-traffic' },
|
{ path: '/admin/config/ops-center', label: '运维与回放', key: 'admin-config-ops-center' },
|
||||||
{ path: '/admin/config/auth', label: '权限与角色', key: 'admin-config-auth' },
|
{ path: '/admin/config/system-center', label: '系统与权限', key: 'admin-config-system-center' }
|
||||||
{ path: '/admin/config/device', label: '设备接入', key: 'admin-config-device' },
|
|
||||||
{ path: '/admin/config/scenario', label: '场景模板', key: 'admin-config-scenario' },
|
|
||||||
{ path: '/admin/config/location', label: '库位管理', key: 'admin-config-location' },
|
|
||||||
{ path: '/admin/config/ops', label: '运营维护', key: 'admin-config-ops' },
|
|
||||||
{ path: '/admin/config/widget', label: '自定义控件', key: 'admin-config-widget' }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import type {
|
|||||||
const PAGES: PageDef[] = [
|
const PAGES: PageDef[] = [
|
||||||
{ key: 'admin-dashboard', label: '总览', group: '概览', scope: 'Platform' },
|
{ key: 'admin-dashboard', label: '总览', group: '概览', scope: 'Platform' },
|
||||||
{ key: 'admin-map-monitor', label: '地图监控', group: '概览', scope: 'Platform' },
|
{ key: 'admin-map-monitor', label: '地图监控', group: '概览', scope: 'Platform' },
|
||||||
{ key: 'admin-playback', label: '调度回放', group: '概览', scope: 'Platform' },
|
|
||||||
{ key: 'admin-maps', label: '地图管理', group: '设计与编排', scope: 'Platform' },
|
{ key: 'admin-maps', label: '地图管理', group: '设计与编排', scope: 'Platform' },
|
||||||
{ key: 'admin-map-editor', label: '地图编辑', group: '设计与编排', scope: 'Platform' },
|
{ key: 'admin-map-editor', label: '地图编辑', group: '设计与编排', scope: 'Platform' },
|
||||||
{ key: 'admin-project-properties', label: '项目属性', group: '设计与编排', scope: 'Platform' },
|
{ key: 'admin-project-properties', label: '项目属性', group: '设计与编排', scope: 'Platform' },
|
||||||
@@ -20,21 +19,13 @@ const PAGES: PageDef[] = [
|
|||||||
{ key: 'admin-cars', label: '车辆管理', group: '设计与编排', scope: 'Platform' },
|
{ key: 'admin-cars', label: '车辆管理', group: '设计与编排', scope: 'Platform' },
|
||||||
{ key: 'admin-processes', label: '进程管理', group: '设计与编排', scope: 'Platform' },
|
{ key: 'admin-processes', label: '进程管理', group: '设计与编排', scope: 'Platform' },
|
||||||
{ key: 'admin-scripts', label: '脚本管理', group: '设计与编排', scope: 'Platform' },
|
{ key: 'admin-scripts', label: '脚本管理', group: '设计与编排', scope: 'Platform' },
|
||||||
{ key: 'admin-missions', label: '任务编排', group: '设计与编排', scope: 'Platform' },
|
{ key: 'admin-task-templates', label: '任务编排', group: '设计与编排', scope: 'Platform' },
|
||||||
{ key: 'admin-config-system', label: '系统级配置', group: '平台配置中心', scope: 'Platform' },
|
{ key: 'admin-config-strategy', label: '调度策略', group: '平台配置中心', scope: 'Platform' },
|
||||||
{ key: 'admin-config-integrations', label: '外部系统对接', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'admin-config-routing', label: '路径规划', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'admin-vehicle-hub', label: '车辆运维', group: '平台配置中心', scope: 'Platform' },
|
{ key: 'admin-vehicle-hub', label: '车辆运维', group: '平台配置中心', scope: 'Platform' },
|
||||||
{ key: 'admin-config-charge', label: '充电策略', group: '平台配置中心', scope: 'Platform' },
|
{ key: 'admin-config-facility', label: '设备与库位', group: '平台配置中心', scope: 'Platform' },
|
||||||
{ key: 'admin-config-task', label: '任务分配', group: '平台配置中心', scope: 'Platform' },
|
{ key: 'admin-config-business', label: '业务与集成', group: '平台配置中心', scope: 'Platform' },
|
||||||
{ key: 'admin-config-traffic', label: '交通管制', group: '平台配置中心', scope: 'Platform' },
|
{ key: 'admin-config-ops-center', label: '运维与回放', group: '平台配置中心', scope: 'Platform' },
|
||||||
{ key: 'admin-config-auth', label: '权限与角色', group: '平台配置中心', scope: 'Platform' },
|
{ key: 'admin-config-system-center', label: '系统与权限', group: '平台配置中心', scope: 'Platform' },
|
||||||
{ key: 'admin-config-device', label: '设备接入', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'admin-config-scenario', label: '场景模板', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'admin-config-location', label: '库位管理', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'admin-config-ops', label: '运营维护', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'admin-config-widget', label: '自定义控件', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'admin-config-map-monitor', label: '地图监控配置', group: '平台配置中心', scope: 'Platform' },
|
|
||||||
{ key: 'monitor-dashboard', label: '运营总览', group: '运营监控', scope: 'RCSMonitor' },
|
{ key: 'monitor-dashboard', label: '运营总览', group: '运营监控', scope: 'RCSMonitor' },
|
||||||
{ key: 'monitor-vehicle-hub', label: '车辆运维', group: '运营监控', scope: 'RCSMonitor' },
|
{ key: 'monitor-vehicle-hub', label: '车辆运维', group: '运营监控', scope: 'RCSMonitor' },
|
||||||
{ key: 'monitor-map', label: '地图监控', group: '运营监控', scope: 'RCSMonitor' },
|
{ key: 'monitor-map', label: '地图监控', group: '运营监控', scope: 'RCSMonitor' },
|
||||||
@@ -145,7 +136,23 @@ function sanitizePages(pages: string[]): string[] {
|
|||||||
const valid = new Set(PAGES.map((p) => p.key))
|
const valid = new Set(PAGES.map((p) => p.key))
|
||||||
const legacy: Record<string, string> = {
|
const legacy: Record<string, string> = {
|
||||||
'admin-config-vehicle': 'admin-vehicle-hub',
|
'admin-config-vehicle': 'admin-vehicle-hub',
|
||||||
'admin-config-fleet': 'admin-vehicle-hub'
|
'admin-config-fleet': 'admin-vehicle-hub',
|
||||||
|
// 会话 16:配置中心收敛为 6 个聚合页,旧页面 Key 迁移到对应聚合页 Key。
|
||||||
|
'admin-config-routing': 'admin-config-strategy',
|
||||||
|
'admin-config-task': 'admin-config-strategy',
|
||||||
|
'admin-config-traffic': 'admin-config-strategy',
|
||||||
|
'admin-config-charge': 'admin-config-strategy',
|
||||||
|
'admin-config-device': 'admin-config-facility',
|
||||||
|
'admin-config-location': 'admin-config-facility',
|
||||||
|
'admin-config-integrations': 'admin-config-business',
|
||||||
|
'admin-config-scenario': 'admin-config-business',
|
||||||
|
'admin-config-widget': 'admin-config-business',
|
||||||
|
'admin-playback': 'admin-config-ops-center',
|
||||||
|
'admin-config-ops': 'admin-config-ops-center',
|
||||||
|
'admin-config-logs': 'admin-config-ops-center',
|
||||||
|
'admin-config-map-monitor': 'admin-config-ops-center',
|
||||||
|
'admin-config-system': 'admin-config-system-center',
|
||||||
|
'admin-config-auth': 'admin-config-system-center'
|
||||||
}
|
}
|
||||||
return [...new Set(pages.map((p) => legacy[p] ?? p).filter((p) => valid.has(p)))]
|
return [...new Set(pages.map((p) => legacy[p] ?? p).filter((p) => valid.has(p)))]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,27 +36,36 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{ path: 'cars', name: 'admin-cars', component: () => import('@/views/admin/CarPanelView.vue'), meta: { title: '车辆管理' } },
|
{ path: 'cars', name: 'admin-cars', component: () => import('@/views/admin/CarPanelView.vue'), meta: { title: '车辆管理' } },
|
||||||
{ path: 'processes', name: 'admin-processes', component: () => import('@/views/admin/ProcessPanelView.vue'), meta: { title: '进程管理' } },
|
{ path: 'processes', name: 'admin-processes', component: () => import('@/views/admin/ProcessPanelView.vue'), meta: { title: '进程管理' } },
|
||||||
{ path: 'scripts', name: 'admin-scripts', component: () => import('@/views/admin/ScriptPanelView.vue'), meta: { title: '脚本管理' } },
|
{ path: 'scripts', name: 'admin-scripts', component: () => import('@/views/admin/ScriptPanelView.vue'), meta: { title: '脚本管理' } },
|
||||||
{ path: 'missions', name: 'admin-missions', component: () => import('@/views/admin/MissionEditorView.vue'), meta: { title: '任务编排' } },
|
{ path: 'task-templates', name: 'admin-task-templates', component: () => import('@/views/admin/TaskTemplateView.vue'), meta: { title: '任务编排' } },
|
||||||
{ path: 'project-properties', name: 'admin-project-properties', component: () => import('@/views/admin/ProjectPropertiesView.vue'), meta: { title: '项目属性' } },
|
{ path: 'project-properties', name: 'admin-project-properties', component: () => import('@/views/admin/ProjectPropertiesView.vue'), meta: { title: '项目属性' } },
|
||||||
{ path: 'playback', name: 'admin-playback', component: () => import('@/views/admin/PlaybackView.vue'), meta: { title: '调度回放' } },
|
// ── 平台配置中心:聚合页(每个聚合页一个 page key = route.name,对齐后端 PageCatalog)。
|
||||||
{ path: 'config/system', name: 'admin-config-system', component: () => import('@/views/admin/config/SystemConfigView.vue'), meta: { title: '系统级配置' } },
|
// 原十余个独立配置页按业务收敛为下列 6 个入口,子页改为聚合页内的 tab。 ──
|
||||||
{ path: 'config/integrations', name: 'admin-config-integrations', component: () => import('@/views/admin/config/ExternalIntegrationView.vue'), meta: { title: '外部系统对接' } },
|
{ path: 'config/strategy', name: 'admin-config-strategy', component: () => import('@/views/admin/config/StrategyConfigView.vue'), meta: { title: '调度策略' } },
|
||||||
{ path: 'config/routing', name: 'admin-config-routing', component: () => import('@/views/admin/config/RoutingPolicyView.vue'), meta: { title: '路径规划策略' } },
|
|
||||||
{ path: 'config/vehicle-hub', name: 'admin-vehicle-hub', component: () => import('@/views/shared/VehicleHubView.vue'), meta: { title: '车辆运维' } },
|
{ path: 'config/vehicle-hub', name: 'admin-vehicle-hub', component: () => import('@/views/shared/VehicleHubView.vue'), meta: { title: '车辆运维' } },
|
||||||
|
{ path: 'config/facility', name: 'admin-config-facility', component: () => import('@/views/admin/config/FacilityConfigView.vue'), meta: { title: '设备与库位' } },
|
||||||
|
{ path: 'config/business', name: 'admin-config-business', component: () => import('@/views/admin/config/BusinessConfigView.vue'), meta: { title: '业务与集成' } },
|
||||||
|
{ path: 'config/ops-center', name: 'admin-config-ops-center', component: () => import('@/views/admin/config/OpsCenterView.vue'), meta: { title: '运维与回放' } },
|
||||||
|
{ path: 'config/system-center', name: 'admin-config-system-center', component: () => import('@/views/admin/config/SystemCenterView.vue'), meta: { title: '系统与权限' } },
|
||||||
|
|
||||||
|
// ── 旧路径深链接兼容:redirect 到聚合页对应 tab(无 name → 不计入受权限管理的页面)。 ──
|
||||||
|
{ path: 'playback', redirect: { path: '/admin/config/ops-center', query: { tab: 'playback' } } },
|
||||||
{ path: 'vehicle-hub', redirect: '/admin/config/vehicle-hub' },
|
{ path: 'vehicle-hub', redirect: '/admin/config/vehicle-hub' },
|
||||||
// 旧独立配置页已合并进车辆运维 Tab,保留深链接兼容。
|
|
||||||
{ path: 'config/vehicle', redirect: { path: '/admin/config/vehicle-hub', query: { tab: 'maintenance' } } },
|
{ path: 'config/vehicle', redirect: { path: '/admin/config/vehicle-hub', query: { tab: 'maintenance' } } },
|
||||||
{ path: 'config/fleet', redirect: { path: '/admin/config/vehicle-hub', query: { tab: 'fleet' } } },
|
{ path: 'config/fleet', redirect: { path: '/admin/config/vehicle-hub', query: { tab: 'fleet' } } },
|
||||||
{ path: 'config/charge', name: 'admin-config-charge', component: () => import('@/views/admin/config/ChargePolicyView.vue'), meta: { title: '充电逻辑' } },
|
{ path: 'config/routing', redirect: { path: '/admin/config/strategy', query: { tab: 'routing' } } },
|
||||||
{ path: 'config/task', name: 'admin-config-task', component: () => import('@/views/admin/config/TaskAllocationView.vue'), meta: { title: '任务分配' } },
|
{ path: 'config/task', redirect: { path: '/admin/config/strategy', query: { tab: 'task' } } },
|
||||||
{ path: 'config/traffic', name: 'admin-config-traffic', component: () => import('@/views/admin/config/TrafficRuleView.vue'), meta: { title: '交通管制' } },
|
{ path: 'config/traffic', redirect: { path: '/admin/config/strategy', query: { tab: 'traffic' } } },
|
||||||
{ path: 'config/auth', name: 'admin-config-auth', component: () => import('@/views/admin/config/AuthRoleView.vue'), meta: { title: '权限角色' } },
|
{ path: 'config/charge', redirect: { path: '/admin/config/strategy', query: { tab: 'charge' } } },
|
||||||
{ path: 'config/device', name: 'admin-config-device', component: () => import('@/views/admin/config/DeviceHubView.vue'), meta: { title: '设备接入' } },
|
{ path: 'config/device', redirect: { path: '/admin/config/facility', query: { tab: 'device' } } },
|
||||||
{ path: 'config/scenario', name: 'admin-config-scenario', component: () => import('@/views/admin/config/ScenarioTemplateView.vue'), meta: { title: '场景模板' } },
|
{ path: 'config/location', redirect: { path: '/admin/config/facility', query: { tab: 'location' } } },
|
||||||
{ path: 'config/location', name: 'admin-config-location', component: () => import('@/views/admin/config/LocationView.vue'), meta: { title: '库位管理' } },
|
{ path: 'config/integrations', redirect: { path: '/admin/config/business', query: { tab: 'integrations' } } },
|
||||||
{ path: 'config/ops', name: 'admin-config-ops', component: () => import('@/views/admin/config/OpsConfigView.vue'), meta: { title: '运营维护' } },
|
{ path: 'config/scenario', redirect: { path: '/admin/config/business', query: { tab: 'scenario' } } },
|
||||||
{ path: 'config/widget', name: 'admin-config-widget', component: () => import('@/views/admin/config/CustomWidgetView.vue'), meta: { title: '自定义控件' } },
|
{ path: 'config/widget', redirect: { path: '/admin/config/business', query: { tab: 'widget' } } },
|
||||||
{ path: 'config/map-monitor', name: 'admin-config-map-monitor', component: () => import('@/views/admin/config/MapMonitorConfigView.vue'), meta: { title: '地图监控配置' } }
|
{ path: 'config/ops', redirect: { path: '/admin/config/ops-center', query: { tab: 'ops' } } },
|
||||||
|
{ path: 'config/logs', redirect: { path: '/admin/config/ops-center', query: { tab: 'logs' } } },
|
||||||
|
{ path: 'config/map-monitor', redirect: { path: '/admin/config/ops-center', query: { tab: 'map-monitor' } } },
|
||||||
|
{ path: 'config/system', redirect: { path: '/admin/config/system-center', query: { tab: 'system' } } },
|
||||||
|
{ path: 'config/auth', redirect: { path: '/admin/config/system-center', query: { tab: 'auth' } } }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -392,12 +392,12 @@ const activeMissionCount = computed(() =>
|
|||||||
interface QuickEntry { key: string; label: string; icon: unknown; hint?: string; primary?: boolean; to?: string; action?: () => void }
|
interface QuickEntry { key: string; label: string; icon: unknown; hint?: string; primary?: boolean; to?: string; action?: () => void }
|
||||||
const quickEntries = computed<QuickEntry[]>(() => [
|
const quickEntries = computed<QuickEntry[]>(() => [
|
||||||
{ key: 'platform-config', label: '平台配置', icon: Setting, primary: true, hint: '进入地图编辑 / 平台搭建(map-editor)', to: '/admin/map-editor' },
|
{ key: 'platform-config', label: '平台配置', icon: Setting, primary: true, hint: '进入地图编辑 / 平台搭建(map-editor)', to: '/admin/map-editor' },
|
||||||
{ key: 'mission', label: '任务编排', icon: Operation, to: '/admin/missions' },
|
{ key: 'mission', label: '任务编排', icon: Operation, to: '/admin/task-templates' },
|
||||||
{ key: 'cars', label: 'AGV 配置', icon: Van, to: '/admin/cars' },
|
{ key: 'cars', label: 'AGV 配置', icon: Van, to: '/admin/cars' },
|
||||||
{ key: 'auth', label: '权限配置', icon: Avatar, to: '/admin/config/auth' },
|
{ key: 'auth', label: '权限配置', icon: Avatar, to: '/admin/config/system-center?tab=auth' },
|
||||||
{ key: 'system', label: '系统配置', icon: Tools, to: '/admin/config/system' },
|
{ key: 'system', label: '系统配置', icon: Tools, to: '/admin/config/system-center?tab=system' },
|
||||||
{ key: 'ops', label: '异常处理', icon: Warning, to: '/admin/config/ops' },
|
{ key: 'ops', label: '异常处理', icon: Warning, to: '/admin/config/ops-center?tab=ops' },
|
||||||
{ key: 'tasks', label: '任务管理', icon: List, to: '/admin/config/task' },
|
{ key: 'tasks', label: '任务管理', icon: List, to: '/admin/config/strategy?tab=task' },
|
||||||
{ key: 'add', label: '添加', icon: Plus, hint: '自定义快捷入口(待实现)', action: () => { ElMessage.info('自定义快捷入口 — 即将在 v1.8 中开放') } }
|
{ key: 'add', label: '添加', icon: Plus, hint: '自定义快捷入口(待实现)', action: () => { ElMessage.info('自定义快捷入口 — 即将在 v1.8 中开放') } }
|
||||||
])
|
])
|
||||||
function onQuickClick(item: QuickEntry) {
|
function onQuickClick(item: QuickEntry) {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="mission-page">
|
|
||||||
<ReflectionManagerPanel
|
|
||||||
kind="process"
|
|
||||||
kind-label="任务"
|
|
||||||
title="任务编排(Mission / 进程,含插件 MissionType 实例化)"
|
|
||||||
empty-text="当前没有任务;点击右上角「新建任务」从已加载的 MissionType 中选一个实例化。"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
/**
|
|
||||||
* /admin/missions 路由的页面入口。
|
|
||||||
*
|
|
||||||
* 由于「任务」与「进程」在后端 ReflectionApiController 共用 kind=process / mission
|
|
||||||
* (UiDiscoveryCache.MissionCreatableTypes 同源),这里直接用 ReflectionManagerPanel
|
|
||||||
* 接入,按下「新建任务」会列出所有 MissionType 子类(含 taskflow / trigger)。
|
|
||||||
*
|
|
||||||
* 旧版本的 DataTablePro + listMissions mock 已经下线,所有数据走 SimpleLite 反射 API。
|
|
||||||
*/
|
|
||||||
import ReflectionManagerPanel from '@/components/reflection/ReflectionManagerPanel.vue'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.mission-page {
|
|
||||||
height: calc(100vh - 56px);
|
|
||||||
padding: 12px 14px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="orchestration-page">
|
|
||||||
<el-tabs v-model="tab" class="orch-tabs" type="border-card" @tab-change="onTabChange">
|
|
||||||
<el-tab-pane label="车辆" name="cars">
|
|
||||||
<CarPanelView v-if="tab === 'cars'" />
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="进程" name="process">
|
|
||||||
<MissionEditorView v-if="tab === 'process'" />
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="脚本" name="script">
|
|
||||||
<ReflectionKindTable
|
|
||||||
v-if="tab === 'script'"
|
|
||||||
kind="script"
|
|
||||||
empty-text="脚本(继承 CarProgram 的子类型)未发现可暴露条目"
|
|
||||||
/>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="任务流" name="taskflow">
|
|
||||||
<ReflectionKindTable
|
|
||||||
v-if="tab === 'taskflow'"
|
|
||||||
kind="mission"
|
|
||||||
extra-filter="taskflow"
|
|
||||||
empty-text="未发现任务流条目"
|
|
||||||
/>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="触发器" name="trigger">
|
|
||||||
<ReflectionKindTable
|
|
||||||
v-if="tab === 'trigger'"
|
|
||||||
kind="mission"
|
|
||||||
extra-filter="trigger"
|
|
||||||
empty-text="未发现触发器条目"
|
|
||||||
/>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { onMounted, ref } from 'vue'
|
|
||||||
import CarPanelView from '@/views/admin/CarPanelView.vue'
|
|
||||||
import MissionEditorView from '@/views/admin/MissionEditorView.vue'
|
|
||||||
import ReflectionKindTable from '@/components/orchestration/ReflectionKindTable.vue'
|
|
||||||
|
|
||||||
const tab = ref<'cars' | 'process' | 'script' | 'taskflow' | 'trigger'>('cars')
|
|
||||||
|
|
||||||
function onTabChange(name: string | number) {
|
|
||||||
tab.value = name as typeof tab.value
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const cached = sessionStorage.getItem('orchestration.tab')
|
|
||||||
if (cached) tab.value = cached as typeof tab.value
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.orchestration-page {
|
|
||||||
height: calc(100vh - 56px);
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
.orch-tabs {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.orch-tabs :deep(.el-tabs__content) {
|
|
||||||
height: calc(100% - 40px);
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div class="task-template-page">
|
||||||
|
<WorkflowEditor />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 任务编排页(路由 /admin/task-templates):承接 workflow 可视化编排组件。
|
||||||
|
*
|
||||||
|
* 原独立的 /admin/missions(MissionEditor / 进程实例管理)入口已下线并合并至此,
|
||||||
|
* 这里专注任务流程的可视化编排、模板设计、导入导出和本地流程库。
|
||||||
|
*/
|
||||||
|
import WorkflowEditor from '@/components/workflow/WorkflowEditor.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.task-template-page {
|
||||||
|
height: calc(100vh - 56px);
|
||||||
|
padding: 12px 14px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-template-page :deep(.workflow-editor) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-hub-page">
|
||||||
|
<el-tabs v-model="activeTab" class="hub-tabs">
|
||||||
|
<el-tab-pane name="integrations" label="外部系统对接">
|
||||||
|
<div class="config-pane"><ExternalIntegrationView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="scenario" label="场景模板" lazy>
|
||||||
|
<div class="config-pane"><ScenarioTemplateView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="widget" label="自定义控件" lazy>
|
||||||
|
<div class="config-pane"><CustomWidgetView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import ExternalIntegrationView from '@/views/admin/config/ExternalIntegrationView.vue'
|
||||||
|
import ScenarioTemplateView from '@/views/admin/config/ScenarioTemplateView.vue'
|
||||||
|
import CustomWidgetView from '@/views/admin/config/CustomWidgetView.vue'
|
||||||
|
|
||||||
|
// 聚合页:对外接口、业务场景建模与自定义控件。Tab 与 URL ?tab= 同步。
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const TAB_NAMES = ['integrations', 'scenario', 'widget'] as const
|
||||||
|
type TabName = (typeof TAB_NAMES)[number]
|
||||||
|
function readTab(): TabName {
|
||||||
|
const q = route.query.tab
|
||||||
|
return typeof q === 'string' && (TAB_NAMES as readonly string[]).includes(q) ? (q as TabName) : 'integrations'
|
||||||
|
}
|
||||||
|
const activeTab = ref<TabName>(readTab())
|
||||||
|
watch(activeTab, (t) => {
|
||||||
|
if (route.query.tab !== t) router.replace({ query: { ...route.query, tab: t } })
|
||||||
|
})
|
||||||
|
watch(() => route.query.tab, () => {
|
||||||
|
const next = readTab()
|
||||||
|
if (next !== activeTab.value) activeTab.value = next
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.config-hub-page {
|
||||||
|
padding: 16px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hub-tabs {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__content) {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tab-pane) { height: 100%; }
|
||||||
|
.config-pane {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item) {
|
||||||
|
color: var(--mg-text-muted, rgba(255, 255, 255, 0.65));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item.is-active) {
|
||||||
|
color: var(--mg-text-light, #fff);
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
background-color: var(--mg-accent, var(--el-color-primary));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__nav-wrap::after) {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-hub-page">
|
||||||
|
<el-tabs v-model="activeTab" class="hub-tabs">
|
||||||
|
<el-tab-pane name="device" label="设备接入">
|
||||||
|
<div class="config-pane"><DeviceHubView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="location" label="库位管理" lazy>
|
||||||
|
<div class="config-pane"><LocationView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import DeviceHubView from '@/views/admin/config/DeviceHubView.vue'
|
||||||
|
import LocationView from '@/views/admin/config/LocationView.vue'
|
||||||
|
|
||||||
|
// 聚合页:第三方设备接入与库位管理。Tab 与 URL ?tab= 同步。
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const TAB_NAMES = ['device', 'location'] as const
|
||||||
|
type TabName = (typeof TAB_NAMES)[number]
|
||||||
|
function readTab(): TabName {
|
||||||
|
const q = route.query.tab
|
||||||
|
return typeof q === 'string' && (TAB_NAMES as readonly string[]).includes(q) ? (q as TabName) : 'device'
|
||||||
|
}
|
||||||
|
const activeTab = ref<TabName>(readTab())
|
||||||
|
watch(activeTab, (t) => {
|
||||||
|
if (route.query.tab !== t) router.replace({ query: { ...route.query, tab: t } })
|
||||||
|
})
|
||||||
|
watch(() => route.query.tab, () => {
|
||||||
|
const next = readTab()
|
||||||
|
if (next !== activeTab.value) activeTab.value = next
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.config-hub-page {
|
||||||
|
padding: 16px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hub-tabs {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__content) {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tab-pane) { height: 100%; }
|
||||||
|
.config-pane {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item) {
|
||||||
|
color: var(--mg-text-muted, rgba(255, 255, 255, 0.65));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item.is-active) {
|
||||||
|
color: var(--mg-text-light, #fff);
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
background-color: var(--mg-accent, var(--el-color-primary));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__nav-wrap::after) {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-hub-page">
|
||||||
|
<el-tabs v-model="activeTab" class="hub-tabs">
|
||||||
|
<el-tab-pane name="playback" label="调度回放">
|
||||||
|
<div class="config-pane"><PlaybackView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="ops" label="运营维护" lazy>
|
||||||
|
<div class="config-pane"><OpsConfigView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="logs" label="日志管理" lazy>
|
||||||
|
<div class="config-pane"><LogManagementView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="map-monitor" label="地图监控配置" lazy>
|
||||||
|
<div class="config-pane"><MapMonitorConfigView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import PlaybackView from '@/views/admin/PlaybackView.vue'
|
||||||
|
import OpsConfigView from '@/views/admin/config/OpsConfigView.vue'
|
||||||
|
import LogManagementView from '@/views/admin/LogManagementView.vue'
|
||||||
|
import MapMonitorConfigView from '@/views/admin/config/MapMonitorConfigView.vue'
|
||||||
|
|
||||||
|
// 聚合页:运维与回放(调度回放从顶级菜单移入此处)。Tab 与 URL ?tab= 同步。
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const TAB_NAMES = ['playback', 'ops', 'logs', 'map-monitor'] as const
|
||||||
|
type TabName = (typeof TAB_NAMES)[number]
|
||||||
|
function readTab(): TabName {
|
||||||
|
const q = route.query.tab
|
||||||
|
return typeof q === 'string' && (TAB_NAMES as readonly string[]).includes(q) ? (q as TabName) : 'playback'
|
||||||
|
}
|
||||||
|
const activeTab = ref<TabName>(readTab())
|
||||||
|
watch(activeTab, (t) => {
|
||||||
|
if (route.query.tab !== t) router.replace({ query: { ...route.query, tab: t } })
|
||||||
|
})
|
||||||
|
watch(() => route.query.tab, () => {
|
||||||
|
const next = readTab()
|
||||||
|
if (next !== activeTab.value) activeTab.value = next
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.config-hub-page {
|
||||||
|
padding: 16px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hub-tabs {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__content) {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tab-pane) { height: 100%; }
|
||||||
|
.config-pane {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item) {
|
||||||
|
color: var(--mg-text-muted, rgba(255, 255, 255, 0.65));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item.is-active) {
|
||||||
|
color: var(--mg-text-light, #fff);
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
background-color: var(--mg-accent, var(--el-color-primary));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__nav-wrap::after) {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-hub-page">
|
||||||
|
<el-tabs v-model="activeTab" class="hub-tabs">
|
||||||
|
<el-tab-pane name="routing" label="路径规划">
|
||||||
|
<div class="config-pane"><RoutingPolicyView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="task" label="任务分配" lazy>
|
||||||
|
<div class="config-pane"><TaskAllocationView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="traffic" label="交通管制" lazy>
|
||||||
|
<div class="config-pane"><TrafficRuleView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="charge" label="充电策略" lazy>
|
||||||
|
<div class="config-pane"><ChargePolicyView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import RoutingPolicyView from '@/views/admin/config/RoutingPolicyView.vue'
|
||||||
|
import TaskAllocationView from '@/views/admin/config/TaskAllocationView.vue'
|
||||||
|
import TrafficRuleView from '@/views/admin/config/TrafficRuleView.vue'
|
||||||
|
import ChargePolicyView from '@/views/admin/config/ChargePolicyView.vue'
|
||||||
|
|
||||||
|
// 聚合页:调度运行策略统一入口。Tab 与 URL ?tab= 同步,旧的独立配置路由 redirect 到此页对应 tab。
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const TAB_NAMES = ['routing', 'task', 'traffic', 'charge'] as const
|
||||||
|
type TabName = (typeof TAB_NAMES)[number]
|
||||||
|
function readTab(): TabName {
|
||||||
|
const q = route.query.tab
|
||||||
|
return typeof q === 'string' && (TAB_NAMES as readonly string[]).includes(q) ? (q as TabName) : 'routing'
|
||||||
|
}
|
||||||
|
const activeTab = ref<TabName>(readTab())
|
||||||
|
watch(activeTab, (t) => {
|
||||||
|
if (route.query.tab !== t) router.replace({ query: { ...route.query, tab: t } })
|
||||||
|
})
|
||||||
|
watch(() => route.query.tab, () => {
|
||||||
|
const next = readTab()
|
||||||
|
if (next !== activeTab.value) activeTab.value = next
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.config-hub-page {
|
||||||
|
padding: 16px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hub-tabs {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__content) {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tab-pane) { height: 100%; }
|
||||||
|
.config-pane {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item) {
|
||||||
|
color: var(--mg-text-muted, rgba(255, 255, 255, 0.65));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item.is-active) {
|
||||||
|
color: var(--mg-text-light, #fff);
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
background-color: var(--mg-accent, var(--el-color-primary));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__nav-wrap::after) {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-hub-page">
|
||||||
|
<el-tabs v-model="activeTab" class="hub-tabs">
|
||||||
|
<el-tab-pane name="system" label="系统级配置">
|
||||||
|
<div class="config-pane"><SystemConfigView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="auth" label="权限与角色" lazy>
|
||||||
|
<div class="config-pane"><AuthRoleView /></div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import SystemConfigView from '@/views/admin/config/SystemConfigView.vue'
|
||||||
|
import AuthRoleView from '@/views/admin/config/AuthRoleView.vue'
|
||||||
|
|
||||||
|
// 聚合页:系统级配置与权限角色。Tab 与 URL ?tab= 同步。
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const TAB_NAMES = ['system', 'auth'] as const
|
||||||
|
type TabName = (typeof TAB_NAMES)[number]
|
||||||
|
function readTab(): TabName {
|
||||||
|
const q = route.query.tab
|
||||||
|
return typeof q === 'string' && (TAB_NAMES as readonly string[]).includes(q) ? (q as TabName) : 'system'
|
||||||
|
}
|
||||||
|
const activeTab = ref<TabName>(readTab())
|
||||||
|
watch(activeTab, (t) => {
|
||||||
|
if (route.query.tab !== t) router.replace({ query: { ...route.query, tab: t } })
|
||||||
|
})
|
||||||
|
watch(() => route.query.tab, () => {
|
||||||
|
const next = readTab()
|
||||||
|
if (next !== activeTab.value) activeTab.value = next
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.config-hub-page {
|
||||||
|
padding: 16px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hub-tabs {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__content) {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tab-pane) { height: 100%; }
|
||||||
|
.config-pane {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item) {
|
||||||
|
color: var(--mg-text-muted, rgba(255, 255, 255, 0.65));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__item.is-active) {
|
||||||
|
color: var(--mg-text-light, #fff);
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
background-color: var(--mg-accent, var(--el-color-primary));
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__nav-wrap::after) {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user