
+++ client/resources/img/page/admin_background.jpg
Binary file is not shown |
--- client/resources/img/page/background.jpg
+++ client/resources/img/page/background.jpg
Binary file is not shown |
--- client/resources/scss/admin/login.scss
+++ client/resources/scss/admin/login.scss
... | ... | @@ -17,9 +17,28 @@ |
17 | 17 |
height: 100%; |
18 | 18 |
@include flex-layout(flex, stretch,); |
19 | 19 |
|
20 |
- .background-img{ |
|
20 |
+ .admin-background-img{ |
|
21 | 21 |
width: 50%; |
22 | 22 |
height: 100%; |
23 |
+ background-image: url(#{$url}/page/admin_background.jpg); |
|
24 |
+ background-position: bottom right 10%; |
|
25 |
+ background-size: auto 100%; |
|
26 |
+ position: relative; |
|
27 |
+ |
|
28 |
+ p{ |
|
29 |
+ font-size: var(--tk-fz-heading-md); |
|
30 |
+ color: #0b4dd1; |
|
31 |
+ font-weight: 700; |
|
32 |
+ position: absolute; |
|
33 |
+ top: 5rem; |
|
34 |
+ left: 5rem; |
|
35 |
+ // animation: bounce 1.5s infinite ease-in-out; |
|
36 |
+ } |
|
37 |
+ } |
|
38 |
+ |
|
39 |
+ .background-img{ |
|
40 |
+ width: 100%; |
|
41 |
+ height: 100%; |
|
23 | 42 |
background-image: url(#{$url}/page/background.jpg); |
24 | 43 |
background-position: bottom right 10%; |
25 | 44 |
background-size: auto 100%; |
--- client/views/layout/AdminMenu copy.vue
+++ client/views/layout/AdminMenu copy.vue
... | ... | @@ -101,7 +101,7 @@ |
101 | 101 |
async fnlogOut() { |
102 | 102 |
await this.logout(); |
103 | 103 |
this.$router.push({ |
104 |
- path: "/login.page", |
|
104 |
+ path: "/cmslogin.page", |
|
105 | 105 |
}); |
106 | 106 |
}, |
107 | 107 |
// 캐시 초기화 |
--- client/views/pages/App.vue
+++ client/views/pages/App.vue
... | ... | @@ -10,7 +10,7 @@ |
10 | 10 |
</main> |
11 | 11 |
</div> |
12 | 12 |
<div v-else v-cloak class="user-wrap relative"> |
13 |
- <UserHeader v-if="path != this.$filters.ctxPath('/login.page') && !$route.path.includes('/popup.page')"/> |
|
13 |
+ <UserHeader v-if="path != this.$filters.ctxPath('/login.page') && path != this.$filters.ctxPath('/cmslogin.page') && !$route.path.includes('/popup.page')"/> |
|
14 | 14 |
<main class="main-wrap"> |
15 | 15 |
<Breadcrumb v-if="$route.path !== this.$filters.ctxPath('/adm/main.page') && $route.path !== this.$filters.ctxPath('/main.page')" /> |
16 | 16 |
<router-view /> |
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
... | ... | @@ -169,6 +169,7 @@ |
169 | 169 |
|
170 | 170 |
AppRouter.beforeEach(async (to, from, next) => { |
171 | 171 |
const contextPath = store.state.contextPath; // Context Path 정보 |
172 |
+ const admPath = to.path.includes('/adm'); // 관리자 페이지 여부 (true: 관리자 페이지, false: 사용자 페이지) |
|
172 | 173 |
// const routeExists = AppRouter.getRoutes().some(route => route.path === to.path || (route.name && route.name === to.name)); |
173 | 174 |
// if (!routeExists) { |
174 | 175 |
// next({ name: 'notfound' }); |
... | ... | @@ -215,7 +216,7 @@ |
215 | 216 |
sessionStorage.setItem("redirect", to.fullPath); |
216 | 217 |
|
217 | 218 |
// 메인 페이지 or 로그인 페이지 |
218 |
- if (to.path === filters.ctxPath('/') || to.path.includes('/login.page') || to.path.startsWith(filters.ctxPath('/cmmn/')) || to.path.includes('/searchId.page') || to.path.includes('/resetPswd.page')) { |
|
219 |
+ if (to.path === filters.ctxPath('/') || to.path.includes('/login.page') || to.path.includes('/cmslogin.page') || to.path.startsWith(filters.ctxPath('/cmmn/')) || to.path.includes('/searchId.page') || to.path.includes('/resetPswd.page')) { |
|
219 | 220 |
let path = to.path; |
220 | 221 |
// 게시판일 경우 .page로 끝나는 경로가 있으므로 마지막 '/' 이전 경로로 설정 |
221 | 222 |
if (to.path.includes('BBS_MNG')) { |
--- client/views/pages/AppStore.js
+++ client/views/pages/AppStore.js
... | ... | @@ -92,6 +92,7 @@ |
92 | 92 |
async logout({ commit }) { |
93 | 93 |
try { |
94 | 94 |
const ctx = this.state.contextPath; // 캐시 초기화 전 contextPath 저장 |
95 |
+ const admPath = this.state.path?.includes("/adm") // 캐시 초기화 전 경로 구분 (true: 관리자 페이지, false: 사용자 페이지) |
|
95 | 96 |
const res = await logOutProc(); |
96 | 97 |
alert(res.data.message); |
97 | 98 |
if (res.status == 200) { |
... | ... | @@ -105,7 +106,11 @@ |
105 | 106 |
document.cookie = "refresh=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; |
106 | 107 |
document.cookie = "Authorization=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; |
107 | 108 |
// 4. 로그인 페이지로 이동 |
108 |
- window.location = ctx + "/login.page"; |
|
109 |
+ if(admPath) { |
|
110 |
+ window.location = ctx + "/cmslogin.page"; |
|
111 |
+ } else { |
|
112 |
+ window.location = ctx + "/login.page"; |
|
113 |
+ } |
|
109 | 114 |
} |
110 | 115 |
} catch(error) { |
111 | 116 |
const errorData = error.response.data; |
--- client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
... | ... | @@ -123,7 +123,7 @@ |
123 | 123 |
await saveByLoginPolicy(loginPolicy); |
124 | 124 |
alert('중복 로그인 설정이 저장되었습니다.'); |
125 | 125 |
store.commit("setStoreReset"); |
126 |
- window.location = this.$filters.ctxPath('/login.page'); |
|
126 |
+ window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
127 | 127 |
} catch (err) { |
128 | 128 |
alert('중복 로그인 설정 저장 실패'+ (err.response?.data?.message || err.message)); |
129 | 129 |
this.allowMultipleLogin = this.previousAllowMultipleLogin; |
... | ... | @@ -144,7 +144,7 @@ |
144 | 144 |
await saveByLoginMode(loginMode); |
145 | 145 |
alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
146 | 146 |
store.commit("setStoreReset"); |
147 |
- window.location = this.$filters.ctxPath('/login.page'); |
|
147 |
+ window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
148 | 148 |
} catch (err) { |
149 | 149 |
alert('로그인 방식 저장 실패: ' + (err.response?.data?.message || err.message)); |
150 | 150 |
this.lgnMode = this.previousLgnMode; |
+++ client/views/pages/login/AdminLogin.vue
... | ... | @@ -0,0 +1,195 @@ |
1 | +<template> | |
2 | + <div class="login-page page"> | |
3 | + <div> | |
4 | + <div class="admin-background-img"> | |
5 | + <p> | |
6 | + 콘텐츠 관리 시스템에 오신 것을 환영합니다.<br /> | |
7 | + 원활한 관리와 운영을 위해 로그인하세요. | |
8 | + </p> | |
9 | + </div> | |
10 | + <div class="login-wrap"> | |
11 | + <div class="login"> | |
12 | + <div | |
13 | + :class="{ | |
14 | + 'login-title': true, | |
15 | + 'user-login': !isAdminPage, | |
16 | + }" | |
17 | + > | |
18 | + LOGIN | |
19 | + </div> | |
20 | + <div class="form-group"> | |
21 | + <label for="id" class="login-label">아이디</label> | |
22 | + <input | |
23 | + type="text" | |
24 | + name="" | |
25 | + id="id" | |
26 | + class="form-control md" | |
27 | + placeholder="아이디를 입력하세요" | |
28 | + v-model="member['lgnId']" | |
29 | + /> | |
30 | + </div> | |
31 | + <div class="form-group"> | |
32 | + <label for="pw" class="login-label">비밀번호</label> | |
33 | + <input | |
34 | + type="password" | |
35 | + name="" | |
36 | + id="pw" | |
37 | + class="form-control md" | |
38 | + placeholder="비밀번호를 입력하세요" | |
39 | + v-model="member['pswd']" | |
40 | + @keydown.enter="fnLogin" | |
41 | + /> | |
42 | + </div> | |
43 | + <button | |
44 | + class="btn md main user-btn" | |
45 | + v-if="!isAdminPage" | |
46 | + @click="fnLogin" | |
47 | + @keydown.enter="fnLogin" | |
48 | + > | |
49 | + 로그인 | |
50 | + </button> | |
51 | + <button | |
52 | + class="btn md main" | |
53 | + v-else | |
54 | + @click="fnLogin" | |
55 | + @keydown.enter="fnLogin" | |
56 | + > | |
57 | + 로그인 | |
58 | + </button> | |
59 | + | |
60 | + <div | |
61 | + class="input-group" | |
62 | + v-if="!isAdminPage" | |
63 | + > | |
64 | + <p class="pl10 pr10 cursor" @click="moveSearchId">아이디찾기</p> | |
65 | + <p class="pl10 pr0 cursor" @click="moveResetPswd">비밀번호 초기화</p> | |
66 | + </div> | |
67 | + </div> | |
68 | + </div> | |
69 | + </div> | |
70 | + </div> | |
71 | +</template> | |
72 | + | |
73 | +<script> | |
74 | +import { useStore } from "vuex"; | |
75 | +import store from "../AppStore"; | |
76 | +import { loginProc } from "../../../resources/api/login"; | |
77 | +import queryParams from "../../../resources/js/queryParams"; | |
78 | + | |
79 | +export default { | |
80 | + mixins: [queryParams], | |
81 | + data: () => { | |
82 | + return { | |
83 | + member: { | |
84 | + lgnId: null, | |
85 | + pswd: null, | |
86 | + }, | |
87 | + store: useStore(), | |
88 | + isAdminPage: false, | |
89 | + }; | |
90 | + }, | |
91 | + methods: { | |
92 | + checkAdminPage() { | |
93 | + if ( | |
94 | + this.restoreRedirect("redirect") && | |
95 | + this.restoreRedirect("redirect").includes("/adm/") | |
96 | + ) { | |
97 | + this.isAdminPage = true; | |
98 | + } else { | |
99 | + this.isAdminPage = false; | |
100 | + } | |
101 | + }, | |
102 | + async fnLogin() { | |
103 | + try { | |
104 | + const res = await loginProc(this.member); | |
105 | + if (res.status == 200) { | |
106 | + const loginType = res.headers['login-type']; // 세션/토큰 로그인 구분 | |
107 | + if (loginType === 'J') { | |
108 | + // JWT 방식 | |
109 | + store.commit("setAuthorization", res.headers.authorization); | |
110 | + store.commit("setLoginMode", "J"); | |
111 | + localStorage.setItem("loginMode", "J"); | |
112 | + const base64String = store.state.authorization.split(".")[1]; | |
113 | + const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/"); | |
114 | + const jsonPayload = decodeURIComponent( | |
115 | + atob(base64).split("").map((c) => { | |
116 | + return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); | |
117 | + }).join("") | |
118 | + ); | |
119 | + const mbr = JSON.parse(jsonPayload); | |
120 | + store.commit("setMbrId", mbr.mbrId); | |
121 | + store.commit("setMbrNm", mbr.mbrNm); | |
122 | + store.commit("setRoles", mbr.roles); | |
123 | + } else if (loginType === 'S') { | |
124 | + store.commit("setLoginMode", "S"); | |
125 | + localStorage.setItem("loginMode", "S"); | |
126 | + const mbr = res.data; | |
127 | + store.commit("setAuthorization", null); | |
128 | + store.commit("setMbrId", mbr.mbrId); | |
129 | + store.commit("setMbrNm", mbr.mbrNm); | |
130 | + const roles = mbr.roles.map(r => ({ authority: r.authrtCd })); | |
131 | + store.commit("setRoles", roles); | |
132 | + } else { | |
133 | + alert("알 수 없는 로그인 방식입니다."); | |
134 | + return; | |
135 | + } | |
136 | + const isAdmin = store.state.roles.some(role => role.authority === "ROLE_ADMIN"); | |
137 | + let url = this.restoreRedirect("redirect"); | |
138 | + if (url != null && url != "") { | |
139 | + const ctx = store.state.contextPath; | |
140 | + if (ctx !== "") { | |
141 | + // redirect 값에서 Context Path 추가 | |
142 | + url = this.$filters.ctxPath(url); | |
143 | + } else { | |
144 | + // redirect 값에서 기존 Context Path 제거 | |
145 | + url = url.replace(/^\/[^\/]+/, ""); // 첫 번째 '/' 이후의 경로만 남김 | |
146 | + } | |
147 | + const routeExists = this.$router.getRoutes().some(route => route.path === url); | |
148 | + | |
149 | + if (url == this.$filters.ctxPath("/searchId.page") || url == this.$filters.ctxPath("/resetPswd.page")) { | |
150 | + this.$router.push({ path: this.$filters.ctxPath("/main.page") }); | |
151 | + } else if (routeExists) { | |
152 | + this.$router.push({ path: url }); | |
153 | + } else { | |
154 | + this.$router.push({ | |
155 | + path: isAdmin ? this.$filters.ctxPath("/adm/main.page") : this.$filters.ctxPath("/") | |
156 | + }); | |
157 | + } | |
158 | + } else { | |
159 | + this.$router.push({ | |
160 | + path: isAdmin ? this.$filters.ctxPath("/adm/main.page") : this.$filters.ctxPath("/") | |
161 | + }); | |
162 | + } | |
163 | + | |
164 | + | |
165 | + } | |
166 | + } catch (error) { | |
167 | + alert(error.response.data.message); | |
168 | + } | |
169 | + }, | |
170 | + moveSearchId() { | |
171 | + this.$router.push({ | |
172 | + path: this.$filters.ctxPath("/resetPswd.page"), | |
173 | + query: { | |
174 | + tab: "id", | |
175 | + }, | |
176 | + }); | |
177 | + }, | |
178 | + moveResetPswd() { | |
179 | + this.$router.push({ | |
180 | + path: this.$filters.ctxPath("/resetPswd.page"), | |
181 | + query: { | |
182 | + tab: "pw", | |
183 | + }, | |
184 | + }); | |
185 | + }, | |
186 | + }, | |
187 | + watch: {}, | |
188 | + computed: {}, | |
189 | + components: {}, | |
190 | + created() { | |
191 | + this.checkAdminPage(); | |
192 | + }, | |
193 | + mounted() {}, | |
194 | +}; | |
195 | +</script> |
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
... | ... | @@ -3,8 +3,8 @@ |
3 | 3 |
<div> |
4 | 4 |
<div class="background-img"> |
5 | 5 |
<p> |
6 |
- 콘텐츠 관리 시스템에 오신 것을 환영합니다.<br /> |
|
7 |
- 원활한 관리와 운영을 위해 로그인하세요. |
|
6 |
+ 어서오세요.<br /> |
|
7 |
+ 로그인하세요. |
|
8 | 8 |
</p> |
9 | 9 |
</div> |
10 | 10 |
<div class="login-wrap"> |
--- client/views/themes/tema_v2/css/style.css
+++ client/views/themes/tema_v2/css/style.css
... | ... | @@ -204,6 +204,11 @@ |
204 | 204 |
} |
205 | 205 |
|
206 | 206 |
/* 기업전용 메인 */ |
207 |
+.admin-background-img{ |
|
208 |
+ width: 100%; |
|
209 |
+ height: 100%; |
|
210 |
+ object-position: top center; |
|
211 |
+} |
|
207 | 212 |
.background-img{ |
208 | 213 |
width: 100%; |
209 | 214 |
height: 100%; |
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?