
Merge branch 'master' of http://210.180.118.83/jhpark/cms_frontend
@2278643d0efd79455bdb69695250281e90a0fd6f
--- client/views/common/filters.js
+++ client/views/common/filters.js
... | ... | @@ -12,7 +12,7 @@ |
12 | 12 |
// Context Path를 제외한 URL 생성 |
13 | 13 |
logicalPath(path) { |
14 | 14 |
const contextPath = store.state.contextPath || ''; |
15 |
- return (contextPath !== '/' && path.startsWith(contextPath)) ? path.slice(contextPath.length) : path; |
|
15 |
+ return (contextPath !== '' && path.startsWith(contextPath)) ? path.slice(contextPath.length) : path; |
|
16 | 16 |
}, |
17 | 17 |
|
18 | 18 |
// 아이디 정규식(5~20자의 영문 소문자, 숫자와 특수기호(_),(-)만 사용) |
--- client/views/layout/AdminMenu.vue
+++ client/views/layout/AdminMenu.vue
... | ... | @@ -114,6 +114,11 @@ |
114 | 114 |
// 부모 메뉴 클릭 시 펼치기만 함 |
115 | 115 |
menu.isOpen = !menu.isOpen; |
116 | 116 |
} else { |
117 |
+ if(menu.routerUrl === "") { |
|
118 |
+ // 하위메뉴가 없는 상위메뉴일 시 알림 출력 |
|
119 |
+ alert("하위 메뉴가 존재하지 않습니다."); |
|
120 |
+ return; |
|
121 |
+ } |
|
117 | 122 |
// 2뎁스 또는 3뎁스 선택 시 menuClick 실행 |
118 | 123 |
this.menuClick(menu); |
119 | 124 |
} |
--- client/views/pages/adm/departmentManagement/DepartmentManagement.vue
+++ client/views/pages/adm/departmentManagement/DepartmentManagement.vue
... | ... | @@ -130,7 +130,7 @@ |
130 | 130 |
:checked="selectedMbr.includes(row.loginId)" |
131 | 131 |
@change="() => checkboxChange(row, idx)" |
132 | 132 |
/> |
133 |
- <label for="'check_' + idx"></label> |
|
133 |
+ <label :for="'check_' + idx"></label> |
|
134 | 134 |
</div> |
135 | 135 |
</template> |
136 | 136 |
</ListTable> |
... | ... | @@ -167,7 +167,7 @@ |
167 | 167 |
<div class="modal-title"> |
168 | 168 |
<p>사용자 목록</p> |
169 | 169 |
</div> |
170 |
- <button class="close-btn" @click="modalClose">X</button> |
|
170 |
+ <button class="btn-close" @click="modalClose">X</button> |
|
171 | 171 |
</template> |
172 | 172 |
<ListTable |
173 | 173 |
:className="'admin-list'" |
--- client/views/pages/adm/preferences/commonCodeManagement/CommonCodeManagement.vue
+++ client/views/pages/adm/preferences/commonCodeManagement/CommonCodeManagement.vue
... | ... | @@ -233,9 +233,9 @@ |
233 | 233 |
alert("코드를 입력해주세요."); |
234 | 234 |
return false; |
235 | 235 |
} |
236 |
- const alpha = /^[A-Z_]*$/; |
|
236 |
+ const alpha = /^[a-zA-Z_]*$/; |
|
237 | 237 |
if (!alpha.test(this.viewCode.cd)) { |
238 |
- alert("코드는 영문(대문자)과 언더바(_)만 사용하여 작성해주세요."); |
|
238 |
+ alert("코드는 영문과 언더바(_)만 사용하여 작성해주세요."); |
|
239 | 239 |
return false; |
240 | 240 |
} |
241 | 241 |
if ( |
--- client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
... | ... | @@ -121,9 +121,9 @@ |
121 | 121 |
const loginPolicy = {}; |
122 | 122 |
loginPolicy.allowMultipleLogin = this.allowMultipleLogin; |
123 | 123 |
await saveByLoginPolicy(loginPolicy); |
124 |
- alert('중복 로그인 설정이 저장되었습니다.'); |
|
124 |
+ alert(res.data.message); |
|
125 | 125 |
} catch (err) { |
126 |
- alert('중복 로그인 설정 저장 실패'); |
|
126 |
+ alert(res.data.message); |
|
127 | 127 |
this.allowMultipleLogin = this.previousAllowMultipleLogin; |
128 | 128 |
} |
129 | 129 |
}, |
... | ... | @@ -139,7 +139,7 @@ |
139 | 139 |
try { |
140 | 140 |
const loginMode = {}; |
141 | 141 |
loginMode.lgnMode = this.lgnMode; |
142 |
- // await saveByLoginMode(loginMode); |
|
142 |
+ await saveByLoginMode(loginMode); |
|
143 | 143 |
alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
144 | 144 |
store.commit("setStoreReset"); |
145 | 145 |
window.location = this.$filters.ctxPath('/login.page'); |
... | ... | @@ -167,8 +167,8 @@ |
167 | 167 |
if (!this.validation()) { |
168 | 168 |
return; |
169 | 169 |
} |
170 |
- // const isCheck = confirm("Context Path를 변경하면 로그아웃됩니다.\n계속하시겠습니까?"); |
|
171 |
- const isCheck = confirm("Context Path를 변경하시겠습니까?"); |
|
170 |
+ const isCheck = confirm("Context Path를 변경하면 로그아웃됩니다.\n계속하시겠습니까?"); |
|
171 |
+ // const isCheck = confirm("Context Path를 변경하시겠습니까?"); |
|
172 | 172 |
if (isCheck) { |
173 | 173 |
try { |
174 | 174 |
let ctx = { path: this.cntxtPth }; |
... | ... | @@ -180,11 +180,11 @@ |
180 | 180 |
storeCtx = ''; |
181 | 181 |
} |
182 | 182 |
store.commit("setContextPath", storeCtx); // 캐시 초기화 요청을 보내기 위한 Context Path 정보 저장 |
183 |
- // const cacheRes = await cacheReSet(); // 캐시 초기화 |
|
184 |
- // alert(cacheRes.data.message); |
|
185 |
- // store.commit("setStoreReset"); // 캐시 초기화 후 Store 초기화 |
|
186 |
- // window.location.reload(); // AppRouter 재실행을 위한 페이지 새로고침 |
|
187 |
- window.location.href = `${storeCtx}/adm/main.page`; |
|
183 |
+ const cacheRes = await cacheReSet(); // 캐시 초기화 |
|
184 |
+ store.commit("setStoreReset"); // 캐시 초기화 후 Store 초기화 |
|
185 |
+ store.commit("setContextPath", storeCtx); // 라우터 Context Path 정보 저장 |
|
186 |
+ window.location.href = `${storeCtx}/login.page`; |
|
187 |
+ // window.location.href = `${storeCtx}/adm/main.page`; |
|
188 | 188 |
} else { |
189 | 189 |
alert(res.data.message); |
190 | 190 |
} |
--- client/views/pages/adm/system/contextPath/ContextPathSelectList.vue
... | ... | @@ -1,165 +0,0 @@ |
1 | -<template> | |
2 | - <div class="search-bar"> | |
3 | - <input | |
4 | - type="text" | |
5 | - class="form-control sm" | |
6 | - placeholder="경로를 입력하세요." | |
7 | - v-model="search.searchText" | |
8 | - @keyup.enter="findAll" | |
9 | - /> | |
10 | - | |
11 | - <button class="btn-ico xsm main ico-sch" @click="findAll"> | |
12 | - <span class="sr-only">검색</span> | |
13 | - </button> | |
14 | - </div> | |
15 | - <div class="content-zone"> | |
16 | - <div class="content"> | |
17 | - <div class="scroll"> | |
18 | - <div class="tbl-wrap"> | |
19 | - <ListTable | |
20 | - :className="'data cursor'" | |
21 | - :colgroup="colgroup" | |
22 | - :thead="thead" | |
23 | - :tbody="tbody" | |
24 | - @listClick="fnView" | |
25 | - > | |
26 | - <template v-slot:button="{ row, idx }"> | |
27 | - <button | |
28 | - class="btn-ico md ico-del" | |
29 | - @click.stop="fnDel(row, idx)" | |
30 | - v-if="pageAuth.delAuthrt == 'Y'" | |
31 | - > | |
32 | - </button> | |
33 | - </template> | |
34 | - </ListTable> | |
35 | - </div> | |
36 | - </div> | |
37 | - </div> | |
38 | - </div> | |
39 | - <div class="btn-wrap list"> | |
40 | - <div></div> | |
41 | - <PaginationButton :className="'pagination'" | |
42 | - v-model:currentPage="search.currentPage" | |
43 | - :pagination="search" | |
44 | - :click="findAll" | |
45 | - /> | |
46 | - <button | |
47 | - class="btn sm main" | |
48 | - @click="fnAdd" | |
49 | - v-if="pageAuth.regAuthrt == 'Y'" | |
50 | - > | |
51 | - 등록 | |
52 | - </button> | |
53 | - </div> | |
54 | -</template> | |
55 | - | |
56 | -<script> | |
57 | -import ListTable from "../../../../component/table/ListTable.vue"; | |
58 | -import PaginationButton from "../../../../component/pagination/PaginationButton.vue"; | |
59 | -import { findAll, del } from "../../../../../resources/api/cntxtPth"; | |
60 | -import queryParams from "../../../../../resources/js/queryParams"; | |
61 | -import { toRaw } from "vue"; | |
62 | -import { defaultSearchParams } from "../../../../../resources/js/defaultSearchParams"; | |
63 | - | |
64 | -export default { | |
65 | - mixins: [queryParams], | |
66 | - components: { | |
67 | - ListTable: ListTable, | |
68 | - PaginationButton: PaginationButton, | |
69 | - }, | |
70 | - data() { | |
71 | - return { | |
72 | - // 페이지 컨텍스트 패스 객체 | |
73 | - pageAuth: JSON.parse(localStorage.getItem("vuex")).pageAuth, | |
74 | - | |
75 | - colgroup: ["4%", "20", "25%", "13%", "13%", "5%"], | |
76 | - thead: ["NO", "경로", "사용여부", "등록자", "등록일", "삭제"], | |
77 | - tbody: [], | |
78 | - search: { ...defaultSearchParams }, | |
79 | - list: [], // 컨텍스트 패스 목록 | |
80 | - listCnt: 0, | |
81 | - }; | |
82 | - }, | |
83 | - created() { | |
84 | - this.resotreQueryParams("queryParams"); | |
85 | - this.findAll(); | |
86 | - }, | |
87 | - methods: { | |
88 | - // 목록 조회 | |
89 | - async findAll() { | |
90 | - this.saveQueryParams("queryParams", this.search); // 검색조건 저장 | |
91 | - try { | |
92 | - const res = await findAll(toRaw(this.search)); | |
93 | - this.list = res.data.data.list; | |
94 | - this.listCnt = res.data.data.pagination.totalRecordCount; | |
95 | - this.search = res.data.data.pagination; | |
96 | - this.makeTbody(); | |
97 | - console.log("this.list : ", this.list); | |
98 | - } catch (error) { | |
99 | - // console.log("error : ", error); | |
100 | - } | |
101 | - }, | |
102 | - // 상세 조회 | |
103 | - fnView(idx) { | |
104 | - this.saveQueryParams("queryParams", this.search); // 검색조건 저장 | |
105 | - this.$router.push({ | |
106 | - name: "admContextPathSelectListOne", | |
107 | - query: { | |
108 | - pageId: this.list[idx]["cntxtPthId"], | |
109 | - }, | |
110 | - }); | |
111 | - }, | |
112 | - // 등록 페이지 이동 | |
113 | - fnAdd() { | |
114 | - this.$router.push({ | |
115 | - name: "admContextPathInsert", | |
116 | - }); | |
117 | - }, | |
118 | - // 삭제 | |
119 | - async fnDel(row, idx) { | |
120 | - if (this.list[idx].sysPvsnYn == 0) { | |
121 | - alert("시스템에서 제공하는 정보는 삭제할수 없습니다."); | |
122 | - return; | |
123 | - } | |
124 | - if (!confirm("삭제하시겠습니까?")) { | |
125 | - return; | |
126 | - } | |
127 | - try { | |
128 | - const res = await del(this.list[idx]); | |
129 | - alert(res.data.message); | |
130 | - if (res.status == 200) { | |
131 | - this.findAll(); | |
132 | - } | |
133 | - } catch (error) { | |
134 | - alert("에러가 발생했습니다.\n시스템관리자에게 문의하세요."); | |
135 | - } | |
136 | - }, | |
137 | - // tbody 생성 | |
138 | - makeTbody() { | |
139 | - this.tbody = []; // 초기화 | |
140 | - this.tbody = this.list.map((cntxtPth, index) => { | |
141 | - let id = | |
142 | - this.listCnt - | |
143 | - index - | |
144 | - (this.search.currentPage - 1) * this.search.recordSize; // 번호 | |
145 | - let path = cntxtPth.path; // 경로 | |
146 | - let useYn = cntxtPth.useYn; // 사용여부 | |
147 | - let writer; // 작성자 | |
148 | - let writeDt; // 작성일 | |
149 | - // 수정 이력 확인 후 수정된 경우가 없다면 최초 작성자로 등록 | |
150 | - if (cntxtPth.mdfr == null || cntxtPth.mdfr === "") { | |
151 | - writer = cntxtPth.rgtrNm; | |
152 | - writeDt = cntxtPth.regDt; | |
153 | - } else { | |
154 | - writer = cntxtPth.mdfrNm; | |
155 | - writeDt = cntxtPth.mdfcnDt; | |
156 | - } | |
157 | - return { id, path, useYn, writer, writeDt }; | |
158 | - }); | |
159 | - }, | |
160 | - }, | |
161 | - watch: {}, | |
162 | - computed: {}, | |
163 | - mounted() {}, | |
164 | -}; | |
165 | -</script> |
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
... | ... | @@ -131,7 +131,17 @@ |
131 | 131 |
alert("알 수 없는 로그인 방식입니다."); |
132 | 132 |
return; |
133 | 133 |
} |
134 |
- const url = this.restoreRedirect("redirect"); |
|
134 |
+ |
|
135 |
+ let url = this.restoreRedirect("redirect"); |
|
136 |
+ const ctx = store.state.contextPath; |
|
137 |
+ if (ctx !== "") { |
|
138 |
+ // redirect 값에서 Context Path 추가 |
|
139 |
+ url = this.$filters.ctxPath(url); |
|
140 |
+ } else { |
|
141 |
+ // redirect 값에서 기존 Context Path 제거 |
|
142 |
+ url = url.replace(/^\/[^\/]+/, ""); // 첫 번째 '/' 이후의 경로만 남김 |
|
143 |
+ } |
|
144 |
+ |
|
135 | 145 |
if (url != null && url != "") { |
136 | 146 |
if (url == this.$filters.ctxPath("/searchId.page") || url == this.$filters.ctxPath("/resetPswd.page")) { |
137 | 147 |
this.$router.push({ path: this.$filters.ctxPath("/main.page") }); |
--- server/modules/web/server.js
+++ server/modules/web/server.js
... | ... | @@ -57,9 +57,9 @@ |
57 | 57 |
/** |
58 | 58 |
* @author : 하석형 |
59 | 59 |
* @since : 2023.08.24 |
60 |
- * @dscription : ROOT URL -> index.html |
|
60 |
+ * @dscription : /, /{ContextPath}/ -> index.html |
|
61 | 61 |
*/ |
62 |
-webServer.get("/", function (request, response) { |
|
62 |
+webServer.get(/^\/([^\/]+\/)?$/, function (request, response) { |
|
63 | 63 |
//response.sendFile을 통한 HTTP html reponse (html내용 Streaming) |
64 | 64 |
response.sendFile(`${BASE_DIR}/client/views/index.html`); |
65 | 65 |
}); |
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?