
--- client/views/layout/Header.vue
+++ client/views/layout/Header.vue
... | ... | @@ -1,180 +1,135 @@ |
1 | 1 |
<template> |
2 |
- |
|
3 |
- <header> |
|
4 |
- <div class="header-container w1500"> |
|
5 |
- <div class="logo-wrap"> |
|
6 |
- <router-link :to="{ path: '/' }" class="logo"><img :src="logo" alt=""></router-link> |
|
7 |
- </div> |
|
8 |
- <div class="nav-wrap"> |
|
9 |
- <nav> |
|
10 |
- <ul> |
|
11 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" |
|
12 |
- @click="updateMenuStats('MENU_00000001')">기록물 |
|
13 |
- <div class="submenu"> |
|
14 |
- <p>• <router-link :to="{ path: '/PicHistorySearch.page' }" @click="updateMenuStats('MENU_00000002')">사진 기록물</router-link></p> |
|
15 |
- <div class="hr"></div> |
|
16 |
- <p>• <router-link :to="{ path: '/VideoHistorySearch.page' }" @click="updateMenuStats('MENU_00000003')">영상 기록물</router-link></p> |
|
17 |
- </div> |
|
18 |
- </li> |
|
19 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" |
|
20 |
- @click="updateMenuStats('MENU_00000004')">언론에서 바라본 구미시 |
|
21 |
- <div class="submenu"> |
|
22 |
- <p>• <router-link :to="{ path: '/MediaVideoSearch.page' }" @click="updateMenuStats('MENU_00000005')">미디어 영상</router-link></p> |
|
23 |
- <div class="hr"></div> |
|
24 |
- <p>• <router-link :to="{ path: '/NewsReleaseSearch.page' }" @click="updateMenuStats('MENU_00000006')">보도자료</router-link></p> |
|
25 |
- </div> |
|
26 |
- </li> |
|
27 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" |
|
28 |
- @click="updateMenuStats('MENU_00000007')"><router-link |
|
29 |
- :to="{ path: '/MemberManagement.page' }">회원관리</router-link></li> |
|
30 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" |
|
31 |
- @click="updateMenuStats('MENU_00000008')"><router-link |
|
32 |
- :to="{ path: '/CategoryManagement.page' }">카테고리 관리</router-link></li> |
|
33 |
- |
|
34 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_USER'" |
|
35 |
- @click="updateMenuStats('MENU_00000001')">기록물 |
|
36 |
- <div class="submenu"> |
|
37 |
- <p>• <router-link :to="{ path: '/PicHistorySearch.page' }" @click="updateMenuStats('MENU_00000002')">사진 기록물</router-link></p> |
|
38 |
- <div class="hr"></div> |
|
39 |
- <p>• <router-link :to="{ path: '/VideoHistorySearch.page' }" @click="updateMenuStats('MENU_00000003')">영상 기록물</router-link></p> |
|
40 |
- </div> |
|
41 |
- </li> |
|
42 |
- |
|
43 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_USER'" |
|
44 |
- @click="updateMenuStats('MENU_00000004')">언론에서 바라본 구미시 |
|
45 |
- <div class="submenu"> |
|
46 |
- <p>• <router-link :to="{ path: '/MediaVideoSearch.page' }" @click="updateMenuStats('MENU_00000005')">미디어 영상</router-link></p> |
|
47 |
- <div class="hr"></div> |
|
48 |
- <p>• <router-link :to="{ path: '/NewsReleaseSearch.page' }" @click="updateMenuStats('MENU_00000006')">보도자료</router-link></p> |
|
49 |
- </div> |
|
50 |
- </li> |
|
51 |
- </ul> |
|
52 |
- </nav> |
|
53 |
- </div> |
|
54 |
- <div class="auth-area"> |
|
55 |
- <ul v-if="$store.state.userId != null"> |
|
56 |
- <li><img src="../../resources/images/icon/user-settings-line.png" alt=""> |
|
57 |
- <router-link :to="{ path: '/MyInfo.page' }">{{ $store.state.userNm }}</router-link> |
|
58 |
- </li> |
|
59 |
- <li> |
|
60 |
- <div class="line"></div> |
|
61 |
- </li> |
|
62 |
- <li><img src="../../resources/images/icon/logout-box-line.png" alt=""> |
|
63 |
- <a href="#" @click.prevent="logout">로그아웃</a> |
|
64 |
- </li> |
|
65 |
- </ul> |
|
66 |
- <a href="#" class="all-menu-btn" @click="toggleMenu"><img src="../../resources/images/allmenu.png" |
|
67 |
- alt=""></a> |
|
68 |
- |
|
69 |
- </div> |
|
70 |
- </div> |
|
71 |
- <div class="overlay" v-if="isMenuOpen"> |
|
72 |
- <div class="all-menu"> |
|
73 |
- <button @click="closeMenu" class="closebtn">✕</button> |
|
74 |
- <div class="nav-wrap"> |
|
75 |
- <nav> |
|
76 |
- <ul> |
|
77 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" @click="updateMenuStats('MENU_00000001')"> |
|
78 |
- <h6>기록물</h6> |
|
79 |
- <div class="submenu"> |
|
80 |
- <p>• <router-link :to="{ path: '/PicHistorySearch.page' }" @click="updateMenuStats('MENU_00000002')">사진 기록물</router-link></p> |
|
81 |
- <div class="hr pink"></div> |
|
82 |
- <p>• <router-link :to="{ path: '/VideoHistorySearch.page' }" @click="updateMenuStats('MENU_00000003')">영상 기록물</router-link></p> |
|
83 |
- </div> |
|
84 |
- </li> |
|
85 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" @click="updateMenuStats('MENU_00000004')"> |
|
86 |
- <h6>언론에서 바라본 구미시</h6> |
|
87 |
- <div class="submenu"> |
|
88 |
- <p>• <router-link :to="{ path: '/MediaVideoSearch.page' }" @click="updateMenuStats('MENU_00000004')">미디어 영상</router-link></p> |
|
89 |
- <div class="hr pink"></div> |
|
90 |
- <p>• <router-link :to="{ path: '/NewsReleaseSearch.page' }" @click="updateMenuStats('MENU_00000005')">보도자료</router-link></p> |
|
91 |
- </div> |
|
92 |
- </li> |
|
93 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" @click="updateMenuStats('MENU_00000007')"> |
|
94 |
- <h6>회원관리</h6> |
|
95 |
- <div class="submenu"> |
|
96 |
- <p>• <router-link :to="{ path: '/MemberManagement.page' }" @click="closeMenu">회원관리</router-link></p> |
|
97 |
- </div> |
|
98 |
- </li> |
|
99 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'" @click="updateMenuStats('MENU_00000008')"> |
|
100 |
- <h6>카테고리 관리</h6> |
|
101 |
- <div class="submenu"> |
|
102 |
- <p>• <router-link :to="{ path: '/CategoryManagement.page' }" @click="closeMenu">카테고리 관리</router-link></p> |
|
103 |
- </div> |
|
104 |
- </li> |
|
105 |
- |
|
106 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_USER'" @click="updateMenuStats('MENU_00000001')"> |
|
107 |
- <h6>기록물</h6> |
|
108 |
- <div class="submenu"> |
|
109 |
- <p>• <router-link :to="{ path: '/PicHistorySearch.page' }" @click="updateMenuStats('MENU_00000002')">사진 기록물</router-link></p> |
|
110 |
- <div class="hr pink"></div> |
|
111 |
- <p>• <router-link :to="{ path: '/VideoHistorySearch.page' }" @click="updateMenuStats('MENU_00000003')">영상 기록물</router-link></p> |
|
112 |
- </div> |
|
113 |
- </li> |
|
114 |
- <li v-if="$store.state.roles[0]?.authority === 'ROLE_USER'" @click="updateMenuStats('MENU_00000004')"> |
|
115 |
- <h6>언론에서 바라본 구미시</h6> |
|
116 |
- <div class="submenu"> |
|
117 |
- <p>• <router-link :to="{ path: '/MediaVideoSearch.page' }" @click="updateMenuStats('MENU_00000004')">미디어 영상</router-link></p> |
|
118 |
- <div class="hr pink"></div> |
|
119 |
- <p>• <router-link :to="{ path: '/NewsReleaseSearch.page' }" @click="updateMenuStats('MENU_00000005')">보도자료</router-link></p> |
|
120 |
- </div> |
|
121 |
- </li> |
|
2 |
+ <header> |
|
3 |
+ <div class="header-container w1500"> |
|
4 |
+ <div class="logo-wrap"> |
|
5 |
+ <router-link :to="{ path: '/' }" class="logo"><img :src="logo" alt=""></router-link> |
|
6 |
+ </div> |
|
7 |
+ <template v-if="!$isEmpty($store.state.userId)"> |
|
8 |
+ <div class="nav-wrap"> |
|
9 |
+ <nav> |
|
10 |
+ <ul v-if="$store.state.roles.length > 0"> |
|
11 |
+ <li @click="updateMenuStats('MENU_00000001')">기록물 <div class="submenu"> |
|
12 |
+ <p>• <router-link :to="{ path: '/PicHistorySearch.page' }">사진 기록물</router-link></p> |
|
13 |
+ <div class="hr"></div> |
|
14 |
+ <p>• <router-link :to="{ path: '/VideoHistorySearch.page' }">영상 기록물</router-link></p> |
|
15 |
+ </div> |
|
16 |
+ </li> |
|
17 |
+ <li @click="updateMenuStats('MENU_00000004')">언론에서 바라본 구미시 <div class="submenu"> |
|
18 |
+ <p>• <router-link :to="{ path: '/MediaVideoSearch.page' }">미디어 영상</router-link></p> |
|
19 |
+ <div class="hr"></div> |
|
20 |
+ <p>• <router-link :to="{ path: '/NewsReleaseSearch.page' }">보도자료</router-link></p> |
|
21 |
+ </div> |
|
22 |
+ </li> |
|
23 |
+ <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'"><router-link :to="{ path: '/MemberManagement.page' }">회원관리</router-link></li> |
|
24 |
+ <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'"><router-link :to="{ path: '/CategoryManagement.page' }">카테고리 관리</router-link></li> |
|
122 | 25 |
</ul> |
123 |
- </nav> |
|
124 |
- </div> |
|
125 |
-</div> |
|
126 |
- |
|
26 |
+ </nav> |
|
127 | 27 |
</div> |
128 |
- </header> |
|
28 |
+ <div class="auth-area"> |
|
29 |
+ <ul> |
|
30 |
+ <li><img src="../../resources/images/icon/user-settings-line.png" alt=""> |
|
31 |
+ <router-link :to="{ path: '/MyInfo.page' }">{{ $store.state.userNm }}</router-link> |
|
32 |
+ </li> |
|
33 |
+ <li> |
|
34 |
+ <div class="line"></div> |
|
35 |
+ </li> |
|
36 |
+ <li><img src="../../resources/images/icon/logout-box-line.png" alt=""> |
|
37 |
+ <a href="#" @click.prevent="logout">로그아웃</a> |
|
38 |
+ </li> |
|
39 |
+ </ul> |
|
40 |
+ <a href="#" class="all-menu-btn" @click="toggleMenu"><img src="../../resources/images/allmenu.png" alt=""></a> |
|
41 |
+ </div> |
|
42 |
+ </template> |
|
43 |
+ </div> |
|
44 |
+ <div class="overlay" v-if="isMenuOpen"> |
|
45 |
+ <div class="all-menu"> |
|
46 |
+ <button @click="closeMenu" class="closebtn">✕</button> |
|
47 |
+ <div class="nav-wrap"> |
|
48 |
+ <nav> |
|
49 |
+ <ul> |
|
50 |
+ <li @click="updateMenuStats('MENU_00000001')"> |
|
51 |
+ <h6>기록물</h6> |
|
52 |
+ <div class="submenu"> |
|
53 |
+ <p>• <router-link :to="{ path: '/PicHistorySearch.page' }">사진 기록물</router-link></p> |
|
54 |
+ <div class="hr pink"></div> |
|
55 |
+ <p>• <router-link :to="{ path: '/VideoHistorySearch.page' }">영상 기록물</router-link></p> |
|
56 |
+ </div> |
|
57 |
+ </li> |
|
58 |
+ <li @click="updateMenuStats('MENU_00000004')"> |
|
59 |
+ <h6>언론에서 바라본 구미시</h6> |
|
60 |
+ <div class="submenu"> |
|
61 |
+ <p>• <router-link :to="{ path: '/MediaVideoSearch.page' }">미디어 영상</router-link></p> |
|
62 |
+ <div class="hr pink"></div> |
|
63 |
+ <p>• <router-link :to="{ path: '/NewsReleaseSearch.page' }">보도자료</router-link></p> |
|
64 |
+ </div> |
|
65 |
+ </li> |
|
66 |
+ <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'"> |
|
67 |
+ <h6>회원관리</h6> |
|
68 |
+ <div class="submenu"> |
|
69 |
+ <p>• <router-link :to="{ path: '/MemberManagement.page' }" @click="closeMenu">회원관리</router-link></p> |
|
70 |
+ </div> |
|
71 |
+ </li> |
|
72 |
+ <li v-if="$store.state.roles[0]?.authority === 'ROLE_ADMIN'"> |
|
73 |
+ <h6>카테고리 관리</h6> |
|
74 |
+ <div class="submenu"> |
|
75 |
+ <p>• <router-link :to="{ path: '/CategoryManagement.page' }" @click="closeMenu">카테고리 관리</router-link></p> |
|
76 |
+ </div> |
|
77 |
+ </li> |
|
78 |
+ </ul> |
|
79 |
+ </nav> |
|
80 |
+ </div> |
|
81 |
+ </div> |
|
82 |
+ </div> |
|
83 |
+ </header> |
|
129 | 84 |
</template> |
130 | 85 |
<script> |
131 | 86 |
import { logOutProc } from "../../resources/api/user" |
132 | 87 |
import { updateStatsByMenuId } from "../../resources/api/main" |
133 | 88 |
export default { |
134 |
- data() { |
|
135 |
- return { |
|
136 |
- isMenuOpen: false, |
|
137 |
- // Define the image sources |
|
138 |
- logo: 'client/resources/images/logo.png', |
|
139 |
- }; |
|
89 |
+ data() { |
|
90 |
+ return { |
|
91 |
+ isMenuOpen: false, |
|
92 |
+ // Define the image sources |
|
93 |
+ logo: 'client/resources/images/logo.png', |
|
94 |
+ }; |
|
95 |
+ }, |
|
96 |
+ methods: { |
|
97 |
+ toggleMenu() { |
|
98 |
+ this.isMenuOpen = !this.isMenuOpen; |
|
140 | 99 |
}, |
141 |
- methods: { |
|
142 |
- toggleMenu() { |
|
143 |
- this.isMenuOpen = !this.isMenuOpen; |
|
144 |
- }, |
|
145 |
- // 메뉴 닫기 |
|
146 |
- closeMenu() { |
|
147 |
- this.isMenuOpen = false; |
|
148 |
- }, |
|
149 |
- async updateMenuStats(menuId) { |
|
150 |
- try { |
|
151 |
- const response = await updateStatsByMenuId(menuId); |
|
152 |
- if (response.status === 200) { |
|
153 |
- console.log(`메뉴 ID ${menuId} 통계 업데이트 성공`); |
|
154 |
- } |
|
155 |
- } catch (error) { |
|
156 |
- console.error(`메뉴 ID ${menuId} 통계 업데이트 중 오류:`, error); |
|
157 |
- } |
|
158 |
- }, |
|
159 |
- logout() { |
|
160 |
- // 백엔드 로그아웃 API 호출 |
|
161 |
- logOutProc() |
|
162 |
- .then(() => { |
|
163 |
- console.log('로그아웃 성공 - 서버 측 쿠키 삭제 완료'); |
|
164 |
- this.$store.commit('setStoreReset'); // 로그아웃 성공 후 스토어 초기화 |
|
165 |
- this.$router.push({ path: '/Login.page' }); // 로그인 페이지로 리다이렉트 |
|
166 |
- }) |
|
167 |
- .catch(err => { |
|
168 |
- console.error('로그아웃 처리 중 오류:', err); |
|
169 |
- this.$store.commit('setStoreReset'); // 오류가 있어도 스토어는 초기화 |
|
170 |
- this.$router.push({ path: '/Login.page' }); // 로그인 페이지로 리다이렉트 |
|
171 |
- }); |
|
172 |
- }, |
|
100 |
+ // 메뉴 닫기 |
|
101 |
+ closeMenu() { |
|
102 |
+ this.isMenuOpen = false; |
|
103 |
+ }, |
|
104 |
+ async updateMenuStats(menuId) { |
|
105 |
+ try { |
|
106 |
+ const response = await updateStatsByMenuId(menuId); |
|
107 |
+ if (response.status === 200) { |
|
108 |
+ console.log(`메뉴 ID ${menuId} 통계 업데이트 성공`); |
|
109 |
+ } |
|
110 |
+ } catch (error) { |
|
111 |
+ console.error(`메뉴 ID ${menuId} 통계 업데이트 중 오류:`, error); |
|
112 |
+ } |
|
113 |
+ }, |
|
114 |
+ logout() { |
|
115 |
+ // 백엔드 로그아웃 API 호출 |
|
116 |
+ logOutProc() |
|
117 |
+ .then(() => { |
|
118 |
+ console.log('로그아웃 성공 - 서버 측 쿠키 삭제 완료'); |
|
119 |
+ this.$store.commit('setStoreReset'); // 로그아웃 성공 후 스토어 초기화 |
|
120 |
+ this.$router.push({ path: '/Login.page' }); // 로그인 페이지로 리다이렉트 |
|
121 |
+ }) |
|
122 |
+ .catch(err => { |
|
123 |
+ console.error('로그아웃 처리 중 오류:', err); |
|
124 |
+ this.$store.commit('setStoreReset'); // 오류가 있어도 스토어는 초기화 |
|
125 |
+ this.$router.push({ path: '/Login.page' }); // 로그인 페이지로 리다이렉트 |
|
126 |
+ }); |
|
127 |
+ }, |
|
173 | 128 |
|
174 |
- }, |
|
175 |
- watch: {}, |
|
176 |
- computed: {}, |
|
177 |
- components: {}, |
|
178 |
- mounted() { }, |
|
129 |
+ }, |
|
130 |
+ watch: {}, |
|
131 |
+ computed: {}, |
|
132 |
+ components: {}, |
|
133 |
+ mounted() { }, |
|
179 | 134 |
}; |
180 | 135 |
</script>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
... | ... | @@ -1,5 +1,6 @@ |
1 | 1 |
import { createWebHistory, createRouter } from "vue-router"; |
2 | 2 |
import store from "./AppStore"; |
3 |
+import { updateStatsByMenuId } from "../../resources/api/main"; |
|
3 | 4 |
|
4 | 5 |
// 공통 |
5 | 6 |
import Main from "./main/Main.vue"; |
... | ... | @@ -27,68 +28,144 @@ |
27 | 28 |
// 카테고리 관리 |
28 | 29 |
import CategoryManagement from "./ctgry/CategoryManagement.vue"; |
29 | 30 |
|
31 |
+// 메뉴 ID 매핑 |
|
32 |
+const pathToMenuIdMap = { |
|
33 |
+ '/PicHistorySearch.page': 'MENU_00000002', |
|
34 |
+ '/VideoHistorySearch.page': 'MENU_00000003', |
|
35 |
+ '/MediaVideoSearch.page': 'MENU_00000005', |
|
36 |
+ '/NewsReleaseSearch.page': 'MENU_00000006', |
|
37 |
+ '/MemberManagement.page': 'MENU_00000007', |
|
38 |
+ '/CategoryManagement.page': 'MENU_00000008' |
|
39 |
+}; |
|
40 |
+ |
|
30 | 41 |
const routes = [ |
31 | 42 |
// 공통 |
32 |
- { path: "/", name: "MainPage", component: Main, meta: { authorization: ['ROLE_ADMIN', 'ROLE_USER'] } }, |
|
33 |
- { path: "/TotalSearch.page", name: "TotalSearch", component: TotalSearch }, |
|
43 |
+ { |
|
44 |
+ path: "/", name: "MainPage", component: Main, |
|
45 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
46 |
+ }, |
|
47 |
+ { |
|
48 |
+ path: "/TotalSearch.page", name: "TotalSearch", component: TotalSearch, |
|
49 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
50 |
+ }, |
|
34 | 51 |
// 회원관리 |
35 |
- { path: "/Login.page", name: "Login", component: Login }, |
|
36 |
- { path: "/MyInfo.page", name: "MyInfo", component: MyInfo, meta: { authorization: ['ROLE_ADMIN', 'ROLE_USER'] } }, |
|
37 |
- { path: "/MemberManagement.page", name: "MemberManagement", component: MemberManagement }, |
|
52 |
+ { |
|
53 |
+ path: "/Login.page", name: "Login", component: Login, |
|
54 |
+ meta: { requiresAuth: false, } |
|
55 |
+ }, |
|
56 |
+ { |
|
57 |
+ path: "/MyInfo.page", name: "MyInfo", component: MyInfo, |
|
58 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
59 |
+ }, |
|
60 |
+ { |
|
61 |
+ path: "/MemberManagement.page", name: "MemberManagement", component: MemberManagement, |
|
62 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN'] } |
|
63 |
+ }, |
|
38 | 64 |
// 기록물 - 사진 |
39 |
- { path: "/PicHistorySearch.page", name: "PicHistorySearch", component: PicHistorySearch }, |
|
40 |
- { path: "/PicHistoryInsert.page", name: "PicHistoryInsert", component: PicHistoryInsert }, |
|
41 |
- { path: "/PicHistoryDetail.page", name: "PicHistoryDetail", component: PicHistoryDetail }, |
|
65 |
+ { |
|
66 |
+ path: "/PicHistorySearch.page", name: "PicHistorySearch", component: PicHistorySearch, |
|
67 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
68 |
+ }, |
|
69 |
+ { |
|
70 |
+ path: "/PicHistoryInsert.page", name: "PicHistoryInsert", component: PicHistoryInsert, |
|
71 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
72 |
+ }, |
|
73 |
+ { |
|
74 |
+ path: "/PicHistoryDetail.page", name: "PicHistoryDetail", component: PicHistoryDetail, |
|
75 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
76 |
+ }, |
|
42 | 77 |
// 기록물 - 영상 |
43 |
- { path: "/VideoHistorySearch.page", name: "VideoHistorySearch", component: VideoHistorySearch }, |
|
44 |
- { path: "/VideoHistoryInsert.page", name: "VideoHistoryInsert", component: VideoHistoryInsert }, |
|
45 |
- { path: "/VideoHistoryDetail.page", name: "VideoHistoryDetail", component: VideoHistoryDetail }, |
|
78 |
+ { |
|
79 |
+ path: "/VideoHistorySearch.page", name: "VideoHistorySearch", component: VideoHistorySearch, |
|
80 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
81 |
+ }, |
|
82 |
+ { |
|
83 |
+ path: "/VideoHistoryInsert.page", name: "VideoHistoryInsert", component: VideoHistoryInsert, |
|
84 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
85 |
+ }, |
|
86 |
+ { |
|
87 |
+ path: "/VideoHistoryDetail.page", name: "VideoHistoryDetail", component: VideoHistoryDetail, |
|
88 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
89 |
+ }, |
|
46 | 90 |
// 미디어 영상 |
47 |
- { path: "/MediaVideoSearch.page", name: "MediaVideoSearch", component: MediaVideoSearch }, |
|
48 |
- { path: "/MediaVideoInsert.page", name: "MediaVideoInsert", component: MediaVideoInsert }, |
|
49 |
- { path: "/MediaVideoDetail.page", name: "MediaVideoDetail", component: MediaVideoDetail }, |
|
91 |
+ { |
|
92 |
+ path: "/MediaVideoSearch.page", name: "MediaVideoSearch", component: MediaVideoSearch, |
|
93 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
94 |
+ }, |
|
95 |
+ { |
|
96 |
+ path: "/MediaVideoInsert.page", name: "MediaVideoInsert", component: MediaVideoInsert, |
|
97 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
98 |
+ }, |
|
99 |
+ { |
|
100 |
+ path: "/MediaVideoDetail.page", name: "MediaVideoDetail", component: MediaVideoDetail, |
|
101 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
102 |
+ }, |
|
50 | 103 |
// 보도자료 |
51 |
- { path: "/NewsReleaseSearch.page", name: "NewsReleaseSearch", component: NewsReleaseSearch }, |
|
52 |
- { path: "/NewsReleaseInsert.page", name: "NewsReleaseInsert", component: NewsReleaseInsert }, |
|
53 |
- { path: "/NewsReleaseDetail.page", name: "NewsReleaseDetail", component: NewsReleaseDetail }, |
|
104 |
+ { |
|
105 |
+ path: "/NewsReleaseSearch.page", name: "NewsReleaseSearch", component: NewsReleaseSearch, |
|
106 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
107 |
+ }, |
|
108 |
+ { |
|
109 |
+ path: "/NewsReleaseInsert.page", name: "NewsReleaseInsert", component: NewsReleaseInsert, |
|
110 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
111 |
+ }, |
|
112 |
+ { |
|
113 |
+ path: "/NewsReleaseDetail.page", name: "NewsReleaseDetail", component: NewsReleaseDetail, |
|
114 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN', 'ROLE_USER'] } |
|
115 |
+ }, |
|
54 | 116 |
// 카테고리 관리 |
55 |
- { path: "/CategoryManagement.page", name: "CategoryManagement", component: CategoryManagement }, |
|
117 |
+ { |
|
118 |
+ path: "/CategoryManagement.page", name: "CategoryManagement", component: CategoryManagement, |
|
119 |
+ meta: { requiresAuth: true, roles: ['ROLE_ADMIN'] } |
|
120 |
+ }, |
|
56 | 121 |
]; |
57 | 122 |
|
58 | 123 |
const AppRouter = createRouter({ |
59 | 124 |
history: createWebHistory(), |
60 | 125 |
routes, |
61 |
- // 모든 라우트 이동 후 페이지 상단으로 스크롤 |
|
62 | 126 |
scrollBehavior() { |
63 | 127 |
return { top: 0 } |
64 | 128 |
}, |
65 | 129 |
}); |
66 | 130 |
|
67 |
-AppRouter.beforeEach((to, from, next) => { |
|
68 |
- const routeExists = AppRouter.getRoutes().some(route => route.path === to.path || (route.name && route.name === to.name)); |
|
69 |
- const userId = store.state.userId; |
|
70 |
- const { authorization } = to.meta; |
|
131 |
+AppRouter.beforeEach(async (to, from, next) => { |
|
132 |
+ // 인증 필요 여부 확인 |
|
133 |
+ const requiresAuth = to.matched.some(record => record.meta.requiresAuth !== false); |
|
71 | 134 |
|
72 |
- // 로그인 상태 확인 |
|
73 |
- const isLoggedIn = userId; |
|
74 |
- |
|
75 |
- // 로그인되지 않은 경우 |
|
76 |
- if (isLoggedIn == null && to.path !== '/Login.page') { |
|
135 |
+ // 로그인 여부 |
|
136 |
+ const isLoggedIn = !!store.state.authorization && !!store.state.userId; |
|
137 |
+ // 로그인이 필요한데 로그인이 안되어 있는 경우 |
|
138 |
+ if (requiresAuth && !isLoggedIn) { |
|
77 | 139 |
alert('로그인이 필요합니다.'); |
78 |
- return next('/Login.page'); // 로그인 페이지로 리다이렉트 |
|
140 |
+ return next('/Login.page'); |
|
79 | 141 |
} |
80 | 142 |
|
81 |
- // 권한이 없을 경우 |
|
82 |
- if (authorization) { |
|
83 |
- if (!authorization.includes(store.state.roles[0].authority)) { |
|
143 |
+ // 이미 로그인했는데 로그인 페이지로 가려는 경우 |
|
144 |
+ if (isLoggedIn && to.path === '/Login.page') { |
|
145 |
+ return next('/'); |
|
146 |
+ } |
|
147 |
+ |
|
148 |
+ // 권한 체크 |
|
149 |
+ if (isLoggedIn && to.meta.roles) { |
|
150 |
+ const userRole = store.state.roles?.[0]?.authority; |
|
151 |
+ |
|
152 |
+ if (!userRole || !to.meta.roles.includes(userRole)) { |
|
84 | 153 |
alert('접근 권한이 없습니다.'); |
85 | 154 |
return next(from.path); |
86 | 155 |
} |
87 | 156 |
} |
88 |
- if (!routeExists) { |
|
89 |
- next('/'); |
|
90 |
- return; |
|
157 |
+ |
|
158 |
+ // 메뉴 통계 업데이트 |
|
159 |
+ const menuId = pathToMenuIdMap[to.path]; |
|
160 |
+ if (menuId) { |
|
161 |
+ try { |
|
162 |
+ await updateStatsByMenuId(menuId); |
|
163 |
+ console.log(`메뉴 통계 업데이트 성공: ${menuId}`); |
|
164 |
+ } catch (error) { |
|
165 |
+ console.log(`메뉴 통계 업데이트 실패: ${menuId}`, error); |
|
166 |
+ } |
|
91 | 167 |
} |
168 |
+ |
|
92 | 169 |
next(); |
93 | 170 |
}); |
94 | 171 |
|
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?