
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="side-content side-menu">
<div class="myinfo simple">
<!-- 사용자 정보 -->
<div class="name-box">
<div class="img-area">
<div>
<img src="/client/resources/img/photo_icon.png" alt="">
<p class="name">OOO과장</p>
</div>
<div class="info">
<p>솔루션 개발팀</p>
<i class="fa-bars"></i>
<p>팀장</p>
</div>
</div>
</div>
<template v-for="section in visibleMenuSections" :key="section.key">
<!-- 일반 드롭다운 메뉴 -->
<details v-for="menu in section.menus" :key="menu.name" class="menu-box" :open="isMenuOpen(menu.name)">
<summary @click.prevent="toggleMenu(menu.name)">
<p>{{ menu.title }}</p>
<div class="icon">
<img src="/client/resources/img/topmenuicon.png" alt="" style="vertical-align: middle;">
</div>
</summary>
<ul>
<li v-for="item in menu.items" :key="item.name">
<router-link :to="{ name: item.name }" exact-active-cl.ass="active-link" v-slot="{ isExactActive }">
<p>{{ item.title }}</p>
<div class="icon" v-if="isExactActive">
<img src="/client/resources/img/menuicon.png" alt="" style="vertical-align: middle;">
</div>
</router-link>
</li>
</ul>
</details>
<!-- 시스템 관리 -->
<ul v-if="section.key === 'system'" class="menu-box danil">
<li v-for="item in section.items" :key="item.name">
<router-link :to="{ name: item.name }" exact-active-class="active-link">
<p>{{ item.title }}</p>
<div class="icon">
<img src="/client/resources/img/menuicon.png" alt="" style="vertical-align: middle;">
</div>
</router-link>
</li>
</ul>
</template>
</div>
</div>
</template>
<script>
// 메뉴 구성 데이터 (외부로 분리 가능)
const MENU_CONFIG = {
sanctn: {
path: '/sanctn-management',
menus: [{
name: 'sanctn',
title: '결재',
items: [
{ name: 'MyApprovalRequestListPage', title: '결재 요청' },
{ name: 'PendingApprovalListPage', title: '승인 대기 목록' }
]
}]
},
attendance: {
path: '/attendance-management',
menus: [
{
name: 'attendance',
title: '근태현황',
items: [
{ name: 'myAttendance', title: '나의 근태현황' },
{ name: 'buseoAttendance', title: '부서별 근태현황' }
]
},
{
name: 'vcatn',
title: '휴가',
items: [
{ name: 'VcatnListPage', title: '휴가 현황' },
{ name: 'VcatnInsertPage', title: '휴가 신청' }
]
},
{
name: 'bsrp',
title: '출장',
items: [
{ name: 'BsrpListPage', title: '출장 현황' },
{ name: 'BsrpInsertPage', title: '출장 신청' }
]
}
]
},
task: {
path: '/task-management',
menus: [{
name: 'project',
title: '프로젝트',
items: [
{ name: 'projectStatue', title: '프로젝트 현황' },
{ name: 'projectInsert', title: '프로젝트 등록' },
{ name: 'projectTuib', title: '투입현황' }
]
}]
},
financial: {
path: '/financial-management',
menus: [
{
name: 'salary',
title: '급여관리',
items: [
{ name: 'salaryList', title: '급여명세서' },
{ name: 'employeeSalaryList', title: '직원별 급여명세서' },
{ name: 'employeeSalaryInsert', title: '급여명세서 등록' }
]
},
{
name: 'expense',
title: '지출관리',
items: [
{ name: 'ChuljangCostList', title: '출장비 현황' },
{ name: '', title: '출장비 설정' },
{ name: 'MeetingCostList', title: '회의비 지출현황' }
]
}
]
},
asset: {
path: '/asset-management',
menus: [
{
name: 'vhcle',
title: '법인차량',
items: [
{ name: 'VhcleList', title: '사용현황' },
{ name: 'VhcleInfoManagement', title: '차량정보 관리' }
]
},
{
name: 'card',
title: '법인카드',
items: [
{ name: 'CardList', title: '사용현황' },
{ name: 'CardInfoManagement', title: '카드정보 관리' }
]
}
]
},
hrm: {
path: '/hrm-management',
menus: [
{
name: 'hrm',
title: '직원',
items: [
{ name: 'HrmSearch', title: '직원검색' },
{ name: 'HrmManagement', title: '직원관리' }
]
},
{
name: 'team',
title: '부서',
items: [
{ name: 'TeamManagement', title: '부서관리' }
]
}
]
},
system: {
path: '/system-management',
items: [
{ name: 'AuthorManagementPage', title: '사용자권한관리' },
{ name: 'MenuAuthorManagementPage', title: '접근제어관리' },
{ name: 'CodeManagementListPage', title: '공통코드관리' }
]
}
}
export default {
name: 'SideMenu',
data: () => ({
openMenus: new Set()
}),
computed: {
currentPath() {
return this.$route.path.toLowerCase()
},
currentRouteName() {
return this.$route.name?.toLowerCase() || ''
},
// 현재 페이지에 맞는 메뉴 섹션만 반환
visibleMenuSections() {
return Object.entries(MENU_CONFIG)
.filter(([_, config]) => this.currentPath.includes(config.path))
.map(([key, config]) => ({ key, ...config }))
}
},
methods: {
isMenuOpen(menuName) {
return this.openMenus.has(menuName) || this.isCurrentMenuActive(menuName)
},
isCurrentMenuActive(menuName) {
const routeChecks = {
sanctn: () => this.currentRouteName.includes('approval'),
attendance: () => ['attendance', 'myattendance', 'buseoattendance'].some(name => this.currentRouteName.includes(name)),
vcatn: () => this.currentRouteName.includes('vcatn'),
bsrp: () => this.currentRouteName.includes('bsrp'),
project: () => this.currentRouteName.includes('project'),
salary: () => this.currentRouteName.includes('salary'),
expense: () => ['cost', 'meeting'].some(name => this.currentRouteName.includes(name)),
vhcle: () => this.currentRouteName.includes('vhcle'),
card: () => this.currentRouteName.includes('card'),
hrm: () => this.currentRouteName.includes('hrm'),
dept: () => this.currentRouteName.includes('buseo')
}
return routeChecks[menuName]?.() || false
},
toggleMenu(menuName) {
if (this.openMenus.has(menuName)) {
this.openMenus.delete(menuName)
} else {
this.openMenus.clear()
this.openMenus.add(menuName)
}
},
updateMenuState() {
this.openMenus.clear()
const activeMenus = Object.keys(MENU_CONFIG).filter(menuName => this.isCurrentMenuActive(menuName))
activeMenus.forEach(menu => this.openMenus.add(menu))
}
},
watch: {
$route: {
handler: 'updateMenuState',
immediate: true
}
}
}
</script>