新增巡檢任務與巡檢設定初頁面,調整側邊欄與麵包屑組件的路由配置

This commit is contained in:
huliang 2025-11-13 17:23:47 +08:00
parent 9bcbad5ee3
commit 0e33a0b64f
6 changed files with 94 additions and 157 deletions

View File

@ -8,17 +8,10 @@
</el-breadcrumb-item> </el-breadcrumb-item>
<el-breadcrumb-item <el-breadcrumb-item
v-for="(item, idx) in breadcrumbs" v-for="(item, idx) in breadcrumbs"
:key="item.path || idx" :key=" idx"
:to=" :to="item.name ? { name: item.name } : undefined"
item.path && idx !== breadcrumbs.length - 1
? { path: item.path }
: undefined
"
> >
<span v-if="!item.path || idx === breadcrumbs.length - 1">{{ <span>{{ item.title }}</span>
item.title || item.name
}}</span>
<span v-else>{{ item.title || item.name }}</span>
</el-breadcrumb-item> </el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</template> </template>
@ -28,84 +21,30 @@ import { computed } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { menuConfig } from "../../constants/menuConfig.js"; import { menuConfig } from "../../constants/menuConfig.js";
// const route = useRoute();
function findMenuItem(route) {
for (const menu of menuConfig) { function findBreadcrumbs(menu, route, path = []) {
for (const child of menu.children) { for (const item of menu) {
// const currentPath = [...path, { title: item.title, name: item.routeName || null }];
if (child.routeName === route.name || child.path === route.path) { if (item.routeName === route.name) {
return { parent: menu, item: child }; if (item.params) {
} const paramsMatch = Object.keys(item.params).every(key => item.params[key] == route.params[key]);
// /plant/:id if (paramsMatch) {
if ( return currentPath;
child.routeName === "PlantInfo" && }
route.path && } else {
route.path.startsWith("/plant/") return currentPath;
) {
return { parent: menu, item: child };
} }
} }
if (item.children) {
const result = findBreadcrumbs(item.children, route, currentPath);
if (result) return result;
}
} }
return null; return null;
} }
function buildBreadcrumb(route) {
const match = findMenuItem(route);
if (!match) return [];
const crumbs = [
{
name: match.parent.title,
title: match.parent.title,
path: null,
meta: { title: match.parent.title },
},
];
let itemTitle = match.item.title;
if (route.name === "PlantInfo" && route.params.id) {
const plantNames = {
"1": "四磺子坪",
"2": "宜蘭大清水",
"3": "宜蘭小清水",
};
itemTitle = plantNames[route.params.id] || match.item.title;
}
crumbs.push({
name: itemTitle,
title: itemTitle,
path: match.item.path,
meta: { title: itemTitle },
});
return crumbs;
}
const route = useRoute();
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {
const menuBreadcrumbs = buildBreadcrumb(route); return findBreadcrumbs(menuConfig, route) || [];
if (menuBreadcrumbs.length > 0) {
return menuBreadcrumbs;
}
const matchedRoutes = route.matched.filter((r) => r.meta && r.meta.title);
if (matchedRoutes.length === 0) {
return [];
}
const currentRoute = matchedRoutes[matchedRoutes.length - 1];
if (currentRoute.meta.parentTitle) {
return [
{
title: currentRoute.meta.parentTitle,
path: null,
},
{
title: currentRoute.meta.title,
path: currentRoute.path,
},
];
}
return matchedRoutes.map((r) => ({
title: r.meta.title,
name: r.name,
path: r.path,
}));
}); });
</script> </script>

View File

@ -16,7 +16,7 @@
<span>結元能源</span> <span>結元能源</span>
</div> </div>
<el-sub-menu v-for="menu in menuConfig" :key="menu.id" :index="menu.id"> <el-sub-menu v-for="menu in menuConfig" :key="menu.title" :index="menu.title">
<template #title> <template #title>
<el-icon> <el-icon>
<component :is="getIconComponent(menu.icon)" /> <component :is="getIconComponent(menu.icon)" />
@ -26,8 +26,8 @@
<el-menu-item <el-menu-item
v-for="item in menu.children" v-for="item in menu.children"
:key="item.id" :key="item.title"
:index="item.path || item.id" :index="item.title"
@click="handleMenuClick(item)" @click="handleMenuClick(item)"
> >
{{ item.title }} {{ item.title }}
@ -73,12 +73,9 @@ const getIconComponent = (iconName) => {
// //
const handleMenuClick = (item) => { const handleMenuClick = (item) => {
if (item.path) { if (item.routeName) {
if (item.routeName && item.params) { router.push({ name: item.routeName, params: item.params || {} });
router.push({ name: item.routeName, params: item.params }); return;
} else {
router.push(item.path);
}
} }
}; };
@ -87,12 +84,12 @@ const activeMenuIndex = computed(() => {
// //
for (const menu of menuConfig) { for (const menu of menuConfig) {
for (const item of menu.children) { for (const item of menu.children) {
if (item.routeName === route.name || item.path === route.path) { if (item.routeName === route.name) {
return item.path || item.id; return item.title;
} }
} }
} }
return route.name || route.path; return '';
}); });
</script> </script>

View File

@ -1,129 +1,102 @@
export const menuConfig = [ export const menuConfig = [
{ {
id: 'overview',
title: '總覽', title: '總覽',
icon: 'Location', icon: 'Location',
children: [ children: [
{ {
id: 'PlantsMap',
title: '地圖總覽', title: '地圖總覽',
path: '/plantsMap',
routeName: 'PlantsMap' routeName: 'PlantsMap'
}, },
{ {
id: 'PlantsOverview',
title: '電廠總覽', title: '電廠總覽',
path: '/plants',
routeName: 'PlantsOverview' routeName: 'PlantsOverview'
} }
] ]
}, },
{ {
id: 'factory-info',
title: '電廠資訊', title: '電廠資訊',
icon: 'Postcard', icon: 'Postcard',
children: [ children: [
{ {
id: 'plant-1',
title: '四磺子坪', title: '四磺子坪',
path: '/plant/1',
routeName: 'PlantInfo', routeName: 'PlantInfo',
params: { id: 1 } params: { id: 1 }
}, },
{ {
id: 'plant-2',
title: '宜蘭大清水', title: '宜蘭大清水',
path: '/plant/2',
routeName: 'PlantInfo', routeName: 'PlantInfo',
params: { id: 2 } params: { id: 2 }
}, },
{ {
id: 'plant-3',
title: '宜蘭小清水', title: '宜蘭小清水',
path: '/plant/3',
routeName: 'PlantInfo', routeName: 'PlantInfo',
params: { id: 3 } params: { id: 3 }
} }
] ]
}, },
{ {
id: 'inspection',
title: '巡檢系統', title: '巡檢系統',
icon: 'DocumentChecked', icon: 'DocumentChecked',
children: [ children: [
{ {
id: 'inspection-task', title: '巡檢任務',
title: '巡檢任務' routeName: 'PatrolMission',
}, },
{ {
id: 'inspection-setting', title: '巡檢設定',
title: '巡檢設定' routeName: 'PatrolSetting',
} }
] ]
}, },
{ {
id: 'report',
title: '報表查詢', title: '報表查詢',
icon: 'DataLine', icon: 'DataLine',
children: [ children: [
{ {
id: 'PlantsReport',
title: '電廠報表', title: '電廠報表',
path: '/plantsReport',
routeName: 'PlantsReport' routeName: 'PlantsReport'
} }
] ]
}, },
{ {
id: 'alert',
title: '即時告警', title: '即時告警',
icon: 'Bell', icon: 'Bell',
children: [ children: [
{ {
id: 'alert-event',
title: '異常事件查詢' title: '異常事件查詢'
} }
] ]
}, },
{ {
id: 'material',
title: '備料管理', title: '備料管理',
icon: 'MessageBox', icon: 'MessageBox',
children: [ children: [
{ {
id: 'material-item',
title: '備品料件管理' title: '備品料件管理'
}, },
{ {
id: 'material-location',
title: '倉庫櫃位管理' title: '倉庫櫃位管理'
} }
] ]
}, },
{ {
id: 'security',
title: '智慧安防', title: '智慧安防',
icon: 'VideoCamera', icon: 'VideoCamera',
children: [ children: [
{ {
id: 'security-system',
title: '安防系統' title: '安防系統'
} }
] ]
}, },
{ {
id: 'system',
title: '系統設定', title: '系統設定',
icon: 'Setting', icon: 'Setting',
children: [ children: [
{ {
id: 'system-factory',
title: '電廠設定', title: '電廠設定',
path: '/plantSetting',
routeName: 'PlantSetting' routeName: 'PlantSetting'
}, },
{ {
id: 'system-account',
title: '帳號設定' title: '帳號設定'
} }
] ]

View File

@ -1,62 +1,51 @@
import { createRouter, createWebHashHistory } from "vue-router"; import { createRouter, createWebHashHistory } from "vue-router";
import Home from "../views/Home.vue"; import Home from "../views/Home.vue";
import PlantsOverview from "../views/PlantsOverview.vue"; import PlantsOverview from "../views/PlantsOverview.vue";
import PatrolMission from "../views/PatrolMission.vue";
import PatrolSetting from "../views/PatrolSetting.vue";
import PlantReport from "../views/PlantReport.vue"; import PlantReport from "../views/PlantReport.vue";
import PlantInfo from "../views/PlantInfo.vue"; import PlantInfo from "../views/PlantInfo.vue";
import PlantSetting from "../views/PlantSetting.vue"; import PlantSetting from "../views/PlantSetting.vue";
const routes = [ const routes = [
{
path: "/",
redirect: "/plantsMap"
},
{ {
path: "/plantsMap", path: "/plantsMap",
name: "PlantsMap", name: "PlantsMap",
component: Home, component: Home
meta: {
title: "地圖總覽",
icon: "Location",
menuGroup: "overview",
parentTitle: "總覽",
},
}, },
{ {
path: "/plants", path: "/plants",
name: "PlantsOverview", name: "PlantsOverview",
component: PlantsOverview, component: PlantsOverview
meta: {
title: "電廠總覽",
icon: "Postcard",
menuGroup: "overview",
parentTitle: "總覽"
},
}, },
{ {
path: "/plant/:id", path: "/plant/:id",
name: "PlantInfo", name: "PlantInfo",
component: PlantInfo, component: PlantInfo
meta: { },
title: "電廠詳細", {
menuGroup: "factory-info", path: "/patrolMission",
parentTitle: "電廠資訊", name: "PatrolMission",
}, component: PatrolMission
},
{
path: "/patrolSetting",
name: "PatrolSetting",
component: PatrolSetting
}, },
{ {
path: "/plantsReport", path: "/plantsReport",
name: "PlantsReport", name: "PlantsReport",
component: PlantReport, component: PlantReport
meta: {
title: "電廠報表",
menuGroup: "report",
parentTitle: "報表查詢",
},
}, },
{ {
path: "/plantSetting", path: "/plantSetting",
name: "PlantSetting", name: "PlantSetting",
component: PlantSetting, component: PlantSetting
meta: {
title: "電廠設定",
menuGroup: "report",
parentTitle: "系統設定",
},
} }
]; ];

View File

@ -0,0 +1,9 @@
<template>
</template>
<script setup>
import { ref, computed } from "vue";
</script>
<style scoped></style>

View File

@ -0,0 +1,30 @@
<template>
<el-row :gutter="20" style="margin-top: 20px">
<el-col :xs="24">
<el-card shadow="always" class="custom-card">
<template #header
><el-radio-group v-model="radio" size="large" fill="#409eff">
<el-radio-button label="樣板管理" value="template" />
<el-radio-button label="任務管理" value="task" /> </el-radio-group
></template>
<div v-if="radio === 'template'">
<!-- 樣板管理內容 -->
<p>這裡是樣板管理</p>
</div>
<div v-if="radio === 'task'">
<!-- 任務管理內容 -->
<p>這裡是任務管理</p>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import { ref } from "vue";
const radio = ref("template");
</script>
<style scoped></style>