|
|
|
|
<template>
|
|
|
|
|
<div class="common-layout">
|
|
|
|
|
<el-container>
|
|
|
|
|
<el-aside class="aside-wrap">
|
|
|
|
|
<RouterLink
|
|
|
|
|
to="/"
|
|
|
|
|
class="layout-logo"
|
|
|
|
|
:class="{ 'layout-logo-collapse': isCollapse }"
|
|
|
|
|
>
|
|
|
|
|
<svg
|
|
|
|
|
class="inline-block text-32px"
|
|
|
|
|
width="1em"
|
|
|
|
|
height="1em"
|
|
|
|
|
viewBox="0 0 160 160"
|
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
>
|
|
|
|
|
<path
|
|
|
|
|
d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z"
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
></path>
|
|
|
|
|
<path
|
|
|
|
|
d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z"
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
></path>
|
|
|
|
|
</svg>
|
|
|
|
|
<h2 class="pl-8px text-16px font-bold" v-show="!isCollapse">
|
|
|
|
|
EPM-工程管理平台
|
|
|
|
|
</h2>
|
|
|
|
|
</RouterLink>
|
|
|
|
|
<el-menu
|
|
|
|
|
class="layout-menu"
|
|
|
|
|
:default-active="activeMenu"
|
|
|
|
|
@select="menuSelect"
|
|
|
|
|
router
|
|
|
|
|
:collapse="isCollapse"
|
|
|
|
|
>
|
|
|
|
|
<template v-for="router in menuList">
|
|
|
|
|
<template v-if="router.meta?.isShow">
|
|
|
|
|
<el-sub-menu
|
|
|
|
|
v-if="router?.children?.filter((item: any) => item.meta?.isShow).length"
|
|
|
|
|
:index="router.path"
|
|
|
|
|
:key="router.path"
|
|
|
|
|
>
|
|
|
|
|
<template #title>
|
|
|
|
|
<div
|
|
|
|
|
:class="router.meta.icon"
|
|
|
|
|
class="menu-icon"
|
|
|
|
|
@click.stop="
|
|
|
|
|
router.path === '/engineering' ? menuSelect(router.path) : null
|
|
|
|
|
"
|
|
|
|
|
></div>
|
|
|
|
|
<span
|
|
|
|
|
@click.stop="
|
|
|
|
|
router.path === '/engineering' ? menuSelect(router.path) : null
|
|
|
|
|
"
|
|
|
|
|
>{{ router.meta.title }}</span
|
|
|
|
|
>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-for="child in router?.children">
|
|
|
|
|
<el-menu-item
|
|
|
|
|
v-if="child?.meta?.isShow"
|
|
|
|
|
:key="child.path"
|
|
|
|
|
:index="
|
|
|
|
|
child.path.startsWith('/')
|
|
|
|
|
? child.path
|
|
|
|
|
: `${router.path}/${child.path}`
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<div :class="child.meta.icon" class="menu-icon"></div>
|
|
|
|
|
<span class="truncate">{{ child.meta.title }}</span>
|
|
|
|
|
</el-menu-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-sub-menu>
|
|
|
|
|
<el-menu-item v-else :index="router.path" :key="router?.path">
|
|
|
|
|
<div :class="router.meta.icon" class="menu-icon"></div>
|
|
|
|
|
<span>{{ router.meta.title }}</span>
|
|
|
|
|
</el-menu-item>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</el-menu>
|
|
|
|
|
</el-aside>
|
|
|
|
|
<el-container>
|
|
|
|
|
<el-header>
|
|
|
|
|
<div class="flex items-center gap-col-2">
|
|
|
|
|
<el-button class="collapes-btn" @click="isCollapse = !isCollapse">
|
|
|
|
|
<div :class="isCollapse ? unfold : fold"></div>
|
|
|
|
|
</el-button>
|
|
|
|
|
<div>
|
|
|
|
|
{{ currentTime }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-header>
|
|
|
|
|
<main class="main-wrap">
|
|
|
|
|
<RouterView />
|
|
|
|
|
</main>
|
|
|
|
|
</el-container>
|
|
|
|
|
</el-container>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { useTheme } from '@/composables/useTheme'
|
|
|
|
|
import { defaultRouter } from '@/router'
|
|
|
|
|
import dayjs from 'dayjs'
|
|
|
|
|
import { getEngineeringList } from '@/api/module/engineering'
|
|
|
|
|
import type { IEngineering } from '@/api/module/engineering/index.d'
|
|
|
|
|
|
|
|
|
|
const unfold = 'i-icon-park-outline:menu-unfold'
|
|
|
|
|
const fold = 'i-icon-park-outline:menu-fold'
|
|
|
|
|
|
|
|
|
|
const { theme } = useTheme()
|
|
|
|
|
|
|
|
|
|
const engineeringList = ref<IEngineering[]>([])
|
|
|
|
|
|
|
|
|
|
const menuList = computed(() => {
|
|
|
|
|
const routes = JSON.parse(JSON.stringify(defaultRouter[0].children))
|
|
|
|
|
const engRoute = routes.find((r: any) => r.path === '/engineering')
|
|
|
|
|
if (engRoute) {
|
|
|
|
|
// Initialize children array
|
|
|
|
|
engRoute.children = []
|
|
|
|
|
|
|
|
|
|
// Add "Overview" item
|
|
|
|
|
engRoute.children.push({
|
|
|
|
|
path: '/engineering',
|
|
|
|
|
meta: {
|
|
|
|
|
title: '工程总览',
|
|
|
|
|
isShow: true,
|
|
|
|
|
icon: 'i-icon-park-outline:all-application',
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Add engineering projects as children
|
|
|
|
|
const projectItems = engineeringList.value.map(item => ({
|
|
|
|
|
path: `/engineering-config/edit?name=${item.name}&version=${item.versions}`,
|
|
|
|
|
meta: {
|
|
|
|
|
title: item.name,
|
|
|
|
|
isShow: true,
|
|
|
|
|
icon: 'i-icon-park-outline:setting-two',
|
|
|
|
|
},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
engRoute.children.push(...projectItems)
|
|
|
|
|
}
|
|
|
|
|
return routes
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const circleUrl = ref(
|
|
|
|
|
'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
|
|
|
|
|
)
|
|
|
|
|
const isCollapse = ref(false)
|
|
|
|
|
|
|
|
|
|
const getIconClass = (icon: string) => {
|
|
|
|
|
return icon
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { push, currentRoute } = useRouter()
|
|
|
|
|
const activeMenu = computed(() => {
|
|
|
|
|
const { meta, path, query } = unref(currentRoute)
|
|
|
|
|
|
|
|
|
|
if (path === '/engineering-config/edit' && query.name) {
|
|
|
|
|
return `/engineering-config/edit?name=${query.name}&version=${query.version}`
|
|
|
|
|
}
|
|
|
|
|
if (['/engineering-config/edit', '/engineering-config/created'].includes(path)) {
|
|
|
|
|
return '/engineering'
|
|
|
|
|
}
|
|
|
|
|
return path
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
function menuSelect(path: string) {
|
|
|
|
|
push(path)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const currentTime = ref('123')
|
|
|
|
|
const updateTime = () => {
|
|
|
|
|
currentTime.value = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
|
requestAnimationFrame(updateTime)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fetchEngineeringList = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await getEngineeringList()
|
|
|
|
|
engineeringList.value = res.list
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
updateTime()
|
|
|
|
|
fetchEngineeringList()
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.common-layout {
|
|
|
|
|
@apply w-full h-full bg-[#F2F3F5];
|
|
|
|
|
|
|
|
|
|
:deep(.el-container) {
|
|
|
|
|
@apply w-full h-full;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-header) {
|
|
|
|
|
@apply h-56 w-full p0 flex items-center justify-between bg-white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-main) {
|
|
|
|
|
@apply p0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-aside) {
|
|
|
|
|
@apply w-auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-menu) {
|
|
|
|
|
@apply h-full px-1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-menu-item.is-active) {
|
|
|
|
|
background-color: rgba(64, 158, 255, 0.1) !important;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-sub-menu .el-menu-item.is-active) {
|
|
|
|
|
background-color: rgba(64, 158, 255, 0.1) !important;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-menu-item:hover:not(.is-active)) {
|
|
|
|
|
background-color: transparent !important;
|
|
|
|
|
color: var(--el-color-primary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-sub-menu .el-menu-item:hover:not(.is-active)) {
|
|
|
|
|
background-color: transparent !important;
|
|
|
|
|
color: var(--el-color-primary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-sub-menu__title:hover) {
|
|
|
|
|
background-color: transparent !important;
|
|
|
|
|
color: var(--el-color-primary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.aside-wrap {
|
|
|
|
|
@apply flex-col;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
height: calc(100vh - 16px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.layout-logo {
|
|
|
|
|
@apply w-full flex-center nowrap-hidden h-56 bg-white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.layout-menu {
|
|
|
|
|
height: calc(100vh - 56px);
|
|
|
|
|
@apply border-r-none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.layout-menu:not(.el-menu--collapse) {
|
|
|
|
|
width: 220px;
|
|
|
|
|
height: calc(100vh - 56px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.layout-logo {
|
|
|
|
|
transition: width 0.3s ease-in-out;
|
|
|
|
|
width: 220px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.layout-logo-collapse {
|
|
|
|
|
width: 64px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-header) {
|
|
|
|
|
@apply p-x-12;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.collapes-btn {
|
|
|
|
|
@apply border-none;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
background-color: rgba(46, 51, 56, 0.09);
|
|
|
|
|
color: rgb(51, 54, 57);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.avatar {
|
|
|
|
|
@apply w-24 h-24;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu-icon {
|
|
|
|
|
@apply m-r-8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.main-wrap {
|
|
|
|
|
height: calc(100vh - 56px);
|
|
|
|
|
@apply p-16;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|