
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
... | ... | @@ -61,8 +61,8 @@ |
61 | 61 |
import buseoManagement from '../pages/Manager/hr/buseoManagement.vue'; |
62 | 62 |
|
63 | 63 |
//시스템관리 |
64 |
-import userManagement from '../pages/Manager/system/userManagement.vue'; |
|
65 |
-import accessControlManagement from '../pages/Manager/system/accessControlManagement.vue'; |
|
64 |
+import AuthorManagementComp from '../pages/Manager/system/AuthorManagement.vue'; |
|
65 |
+import MenuAuthorManagementComp from './Manager/system/MenuAuthorManagement.vue'; |
|
66 | 66 |
import commonCodeManagement from '../pages/Manager/system/commonCodeManagement.vue'; |
67 | 67 |
import commonCodeInsert from '../pages/Manager/system/commonCodeInsert.vue'; |
68 | 68 |
import commonCodeDetail from '../pages/Manager/system/commonCodeDetail.vue'; |
... | ... | @@ -149,10 +149,10 @@ |
149 | 149 |
}, |
150 | 150 |
// 시스템관리 |
151 | 151 |
{ |
152 |
- path: '/system-management', name: 'system', redirect: { name: 'userManagement' }, |
|
152 |
+ path: '/system-management', name: 'system', redirect: { name: 'AuthorManagementPage' }, |
|
153 | 153 |
children: [ |
154 |
- { path: 'userManagement.page', name: 'userManagement', component: userManagement }, |
|
155 |
- { path: 'accessControlManagement.page', name: 'accessControlManagement', component: accessControlManagement }, |
|
154 |
+ { path: 'AuthorManagement.page', name: 'AuthorManagementPage', component: AuthorManagementComp}, |
|
155 |
+ { path: 'MenuAuthorManagement.page', name: 'MenuAuthorManagementPage', component: MenuAuthorManagementComp }, |
|
156 | 156 |
{ path: 'commonCodeManagement.page', name: 'commonCodeManagement', component: commonCodeManagement }, |
157 | 157 |
{ path: 'commonCodeInsert.page', name: 'commonCodeInsert', component: commonCodeInsert }, |
158 | 158 |
{ path: 'commonCodeDetail.page', name: 'commonCodeDetail', component: commonCodeDetail }, |
+++ client/views/pages/Manager/system/AuthorManagement.vue
... | ... | @@ -0,0 +1,256 @@ |
1 | +<template> | |
2 | + <div class="card "> | |
3 | + <div class="card-body "> | |
4 | + <h2 class="card-title">사용자 권한 관리</h2> | |
5 | + <div class="flex align-top"> | |
6 | + <div class="sch-form-wrap search"> | |
7 | + <div class="tbl-wrap table-scroll"> | |
8 | + <table id="myTable" class="tbl data"> | |
9 | + <thead> | |
10 | + <tr> | |
11 | + <th>권한 목록</th> | |
12 | + </tr> | |
13 | + </thead> | |
14 | + <tbody> | |
15 | + <tr v-for="(item, idx) of lists" :key="idx" @click="findData(item.authorCode)"> | |
16 | + <td :class="{ 'selected': selectedAuthor == item.authorCode, 'muted': item.useAt === 'N' }">{{ item.authorNm }}</td> | |
17 | + </tr> | |
18 | + </tbody> | |
19 | + </table> | |
20 | + </div> | |
21 | + </div> | |
22 | + <div> | |
23 | + <div class="sch-form-wrap title-wrap"> | |
24 | + <h3><img :src="h3icon" alt="">권한 정보</h3> | |
25 | + <div class="buttons"> | |
26 | + <button type="button" class="btn sm tertiary" @click="fnResetForm">신규</button> | |
27 | + <button type="button" class="btn sm secondary" v-if="!isEditMode" @click="fnSave">등록</button> | |
28 | + <button type="button" class="btn sm secondary" v-else @click="fnUpdate">수정</button> | |
29 | + <button type="button" class="btn sm btn-red" v-if="isEditMode" @click="fnDelete">삭제</button> | |
30 | + </div> | |
31 | + </div> | |
32 | + <div class="tbl-wrap row g-3 pt-3 needs-validation detail"> | |
33 | + <div class="col-12"> | |
34 | + <label for="authorCode" class="form-label"> | |
35 | + <p>권한코드 <span class="require"><img :src="require" alt=""></span></p> | |
36 | + </label> | |
37 | + <input type="text" class="form-control" id="authorCode" v-model="data.authorCode" /> | |
38 | + </div> | |
39 | + <div class="col-12"> | |
40 | + <label for="authorNm" class="form-label"> | |
41 | + <p>권한명 <span class="require"><img :src="require" alt=""></span></p> | |
42 | + </label> | |
43 | + <input type="text" class="form-control" id="authorNm" v-model="data.authorNm" /> | |
44 | + </div> | |
45 | + <div class="col-12 chuljang "> | |
46 | + <label for="prvonsh" class="form-label">권한설명</label> | |
47 | + <textarea name="dc" id="dc" class="form-control" v-model="data.dc"></textarea> | |
48 | + </div> | |
49 | + <div class="col-12 border-x input-radio"> | |
50 | + <label for="prvonsh" class="form-label"> | |
51 | + <p>사용여부 <span class="require"><img :src="require" alt=""></span></p> | |
52 | + </label> | |
53 | + <div class="chk-area"> | |
54 | + <div class="form-check"> | |
55 | + <input type="radio" name="useAt" id="useAtTrue" value="Y" v-model="data.useAt" :disabled="!hasAuthorCode"> | |
56 | + <label for="useAtTrue">사용</label> | |
57 | + </div> | |
58 | + <div class="form-check"> | |
59 | + <input type="radio" name="useAt" id="useAtFalse" value="N" v-model="data.useAt" :disabled="!hasAuthorCode"> | |
60 | + <label for="useAtFalse">미사용</label> | |
61 | + </div> | |
62 | + </div> | |
63 | + </div> | |
64 | + </div> | |
65 | + </div> | |
66 | + </div> | |
67 | + </div> | |
68 | + </div> | |
69 | +</template> | |
70 | +<script> | |
71 | +// API | |
72 | +import { findAuthorsProc, saveAuthorProc, findAuthorProc, updateAuthorProc, deleteAuthorProc } from '../../../../resources/api/author' | |
73 | + | |
74 | +export default { | |
75 | + data() { | |
76 | + return { | |
77 | + require: "/client/resources/img/require.png", | |
78 | + h3icon: "/client/resources/img/h3icon.png", | |
79 | + | |
80 | + isEditMode: false, // 수정 모드 여부 | |
81 | + selectedAuthor: null, | |
82 | + | |
83 | + initData: { | |
84 | + authorCode: null, // 권한코드 | |
85 | + authorNm: null, // 권한명 | |
86 | + dc: null, // 권한설명 | |
87 | + useAt: "Y", // 사용여부 (Y:사용-기본값 / N:미사용) | |
88 | + }, | |
89 | + | |
90 | + lists: [], // 권한 목록 정보 | |
91 | + data: {}, // 권한 상세 정보 | |
92 | + } | |
93 | + }, | |
94 | + | |
95 | + computed: { | |
96 | + hasAuthorCode() { | |
97 | + return !!(this.data?.authorCode); | |
98 | + } | |
99 | + }, | |
100 | + | |
101 | + created() { | |
102 | + this.fnReset(); // 데이터 초기화 | |
103 | + }, | |
104 | + | |
105 | + mounted() { | |
106 | + this.findList(); // 목록 조회 | |
107 | + }, | |
108 | + | |
109 | + methods: { | |
110 | + // 목록 조회 | |
111 | + async findList() { | |
112 | + try { | |
113 | + const response = await findAuthorsProc(); | |
114 | + const result = response.data.data; | |
115 | + | |
116 | + this.lists = result.authors; | |
117 | + } catch (error) { | |
118 | + if (error.response) { | |
119 | + alert(error.response.data.message); | |
120 | + } else { | |
121 | + alert("에러가 발생했습니다."); | |
122 | + } | |
123 | + console.error(error.message); | |
124 | + }; | |
125 | + }, | |
126 | + | |
127 | + // 상세 조회 (권한 선택 시 실행) | |
128 | + async findData(id) { | |
129 | + try { | |
130 | + this.selectedAuthor = id; | |
131 | + | |
132 | + const response = await findAuthorProc(id); | |
133 | + const result = response.data.data; | |
134 | + | |
135 | + this.data = result.author; | |
136 | + this.isEditMode = true; // 수정 모드로 변경 | |
137 | + } catch (error) { | |
138 | + if (error.response) { | |
139 | + alert(error.response.data.message); | |
140 | + } else { | |
141 | + alert("에러가 발생했습니다."); | |
142 | + } | |
143 | + console.error(error.message); | |
144 | + }; | |
145 | + }, | |
146 | + | |
147 | + // 신규 (리셋) | |
148 | + fnResetForm() { | |
149 | + const isCheck = confirm("신규 등록 화면으로 전환 시, 현재 작업중인 내용이 초기화됩니다.\n전환하시겠습니까?"); | |
150 | + if (!isCheck) { | |
151 | + return; | |
152 | + } | |
153 | + | |
154 | + this.fnReset(); // 데이터 초기화 | |
155 | + }, | |
156 | + | |
157 | + // 데이터 초기화 | |
158 | + fnReset() { | |
159 | + this.data = { ...this.initData }; | |
160 | + this.isEditMode = false; // 신규 모드로 변경 | |
161 | + }, | |
162 | + | |
163 | + // 등록 | |
164 | + async fnSave() { | |
165 | + try { | |
166 | + const data = { | |
167 | + authorCode: this.data.authorCode, | |
168 | + authorNm: this.data.authorNm, | |
169 | + dc: this.data.dc, | |
170 | + } | |
171 | + | |
172 | + const response = await saveAuthorProc(data); | |
173 | + const result = response.data.data; | |
174 | + | |
175 | + alert("등록되었습니다."); | |
176 | + | |
177 | + this.fnReset(); // 데이터 초기화 | |
178 | + this.findList(); // 목록 조회 | |
179 | + } catch (error) { | |
180 | + if (error.response) { | |
181 | + alert(error.response.data.message); | |
182 | + } else { | |
183 | + alert("에러가 발생했습니다."); | |
184 | + } | |
185 | + console.error(error.message); | |
186 | + }; | |
187 | + }, | |
188 | + | |
189 | + // 수정 | |
190 | + async fnUpdate() { | |
191 | + try { | |
192 | + const data = { | |
193 | + authorCode: this.data.authorCode, | |
194 | + authorNm: this.data.authorNm, | |
195 | + dc: this.data.dc, | |
196 | + useAt: this.data.useAt, | |
197 | + } | |
198 | + | |
199 | + const response = await updateAuthorProc(data); | |
200 | + const result = response.data.data; | |
201 | + | |
202 | + alert("수정되었습니다."); | |
203 | + | |
204 | + this.fnReset(); // 데이터 초기화 | |
205 | + this.findList(); // 목록 조회 | |
206 | + } catch (error) { | |
207 | + if (error.response) { | |
208 | + alert(error.response.data.message); | |
209 | + } else { | |
210 | + alert("에러가 발생했습니다."); | |
211 | + } | |
212 | + console.error(error.message); | |
213 | + }; | |
214 | + }, | |
215 | + | |
216 | + // 삭제 | |
217 | + async fnDelete() { | |
218 | + try { | |
219 | + const isCheck = confirm("삭제 할 경우 삭제된 데이터를 복구할 수 없습니다.\n삭제하시겠습니까?"); | |
220 | + if (!isCheck) { | |
221 | + return; | |
222 | + } | |
223 | + | |
224 | + const response = await deleteAuthorProc(this.data.authorCode); | |
225 | + const result = response.data.data; | |
226 | + | |
227 | + alert("삭제되었습니다."); | |
228 | + | |
229 | + this.fnReset(); // 데이터 초기화 | |
230 | + this.findList(); // 목록 조회 | |
231 | + } catch (error) { | |
232 | + if (error.response) { | |
233 | + alert(error.response.data.message); | |
234 | + } else { | |
235 | + alert("에러가 발생했습니다."); | |
236 | + } | |
237 | + console.error(error.message); | |
238 | + }; | |
239 | + }, | |
240 | + }, | |
241 | +} | |
242 | +</script> | |
243 | +<style scoped> | |
244 | +tr { | |
245 | + cursor: pointer; | |
246 | +} | |
247 | + | |
248 | +.tbl-wrap #myTable .muted { | |
249 | + background-color: rgba(255, 255, 255, 0.3); | |
250 | +} | |
251 | + | |
252 | +.tbl-wrap #myTable .selected { | |
253 | + color: #FFFFFF; | |
254 | + background-color: #213F9A; | |
255 | +} | |
256 | +</style>(파일 끝에 줄바꿈 문자 없음) |
+++ client/views/pages/Manager/system/MenuAuthorManagement.vue
... | ... | @@ -0,0 +1,208 @@ |
1 | +<template> | |
2 | + <div class="card"> | |
3 | + <div class="card-body"> | |
4 | + <h2 class="card-title">접근제어관리</h2> | |
5 | + <div class="flex align-top"> | |
6 | + <div class="sch-form-wrap search"> | |
7 | + <div class="tbl-wrap table-scroll"> | |
8 | + <table id="myTable" class="tbl data"> | |
9 | + <thead> | |
10 | + <tr> | |
11 | + <th>권한목록</th> | |
12 | + </tr> | |
13 | + </thead> | |
14 | + <tbody> | |
15 | + <tr v-for="(item, idx) of authorLists" :key="idx" @click="findMenuAuthorList(item.authorCode)"> | |
16 | + <td v-if="item.useAt === 'Y'" :class="{ 'selected': selectedAuthor == item.authorCode }">{{ item.authorNm }}</td> | |
17 | + </tr> | |
18 | + </tbody> | |
19 | + </table> | |
20 | + </div> | |
21 | + </div> | |
22 | + <div style="width: 100%;"> | |
23 | + <div class="tbl-wrap chk-area"> | |
24 | + <table id="myTable" class="tbl data"> | |
25 | + <thead> | |
26 | + <tr> | |
27 | + <th>메뉴명</th> | |
28 | + <th>전체</th> | |
29 | + <th>읽기</th> | |
30 | + <th>쓰기</th> | |
31 | + <th>수정</th> | |
32 | + <th>삭제</th> | |
33 | + </tr> | |
34 | + </thead> | |
35 | + <tbody> | |
36 | + <template v-if="menuAuthorLists.length > 0"> | |
37 | + <tr v-for="(item, idx) in menuAuthorLists" :key="idx"> | |
38 | + <td>{{ item.menuNm }}</td> | |
39 | + <td> | |
40 | + <div class="form-check"> | |
41 | + <input type="checkbox" :id="`all_${idx}`" :checked="isAllChecked(item)" @change="toggleAll(idx)" /> | |
42 | + <label :for="`all_${idx}`"></label> | |
43 | + </div> | |
44 | + </td> | |
45 | + <td> | |
46 | + <div class="form-check"> | |
47 | + <input type="checkbox" :id="`redng_${idx}`" :checked="item.redng === 'Y'" @change="updatePermission(idx, 'redng', $event)" /> | |
48 | + <label :for="`redng_${idx}`"></label> | |
49 | + </div> | |
50 | + </td> | |
51 | + <td> | |
52 | + <div class="form-check"> | |
53 | + <input type="checkbox" :id="`write_${idx}`" :checked="item.write === 'Y'" @change="updatePermission(idx, 'write', $event)" /> | |
54 | + <label :for="`write_${idx}`"></label> | |
55 | + </div> | |
56 | + </td> | |
57 | + <td> | |
58 | + <div class="form-check"> | |
59 | + <input type="checkbox" :id="`updt_${idx}`" :checked="item.updt === 'Y'" @change="updatePermission(idx, 'updt', $event)" /> | |
60 | + <label :for="`updt_${idx}`"></label> | |
61 | + </div> | |
62 | + </td> | |
63 | + <td> | |
64 | + <div class="form-check"> | |
65 | + <input type="checkbox" :id="`delete_${idx}`" :checked="item.delete === 'Y'" @change="updatePermission(idx, 'delete', $event)" /> | |
66 | + <label :for="`delete_${idx}`"></label> | |
67 | + </div> | |
68 | + </td> | |
69 | + </tr> | |
70 | + </template> | |
71 | + <template v-else> | |
72 | + <tr> | |
73 | + <td colspan="6">조회된 정보가 없습니다.</td> | |
74 | + </tr> | |
75 | + </template> | |
76 | + </tbody> | |
77 | + </table> | |
78 | + </div> | |
79 | + <div> | |
80 | + <button type="button" class="btn sm secondary" @click="fnUpdate">저장</button> | |
81 | + </div> | |
82 | + </div> | |
83 | + </div> | |
84 | + </div> | |
85 | + </div> | |
86 | +</template> | |
87 | +<script> | |
88 | +// API | |
89 | +import { findAuthorsProc } from '../../../../resources/api/author' | |
90 | +import { findMenuAuthorsProc, updateMenuAuthorsProc } from '../../../../resources/api/menuAuthor' | |
91 | + | |
92 | +export default { | |
93 | + data() { | |
94 | + return { | |
95 | + selectedAuthor: null, | |
96 | + | |
97 | + authorLists: [], // 권한 목록 정보 | |
98 | + menuAuthorLists: [], // 메뉴 권한 목록 정보 | |
99 | + } | |
100 | + }, | |
101 | + | |
102 | + mounted() { | |
103 | + this.findAuthorList(); // 권한 목록 조회 | |
104 | + }, | |
105 | + | |
106 | + methods: { | |
107 | + // 권한 목록 조회 | |
108 | + async findAuthorList() { | |
109 | + try { | |
110 | + const response = await findAuthorsProc(); | |
111 | + const result = response.data.data; | |
112 | + | |
113 | + this.authorLists = result.authors; | |
114 | + } catch (error) { | |
115 | + if (error.response) { | |
116 | + alert(error.response.data.message); | |
117 | + } else { | |
118 | + alert("에러가 발생했습니다."); | |
119 | + } | |
120 | + console.error(error.message); | |
121 | + }; | |
122 | + }, | |
123 | + | |
124 | + // 메뉴 권한 목록 조회 | |
125 | + async findMenuAuthorList(code) { | |
126 | + try { | |
127 | + this.selectedAuthor = code; | |
128 | + | |
129 | + const response = await findMenuAuthorsProc(this.selectedAuthor); | |
130 | + const result = response.data.data; | |
131 | + | |
132 | + this.menuAuthorLists = result.menuAuthors; | |
133 | + } catch (error) { | |
134 | + if (error.response) { | |
135 | + alert(error.response.data.message); | |
136 | + } else { | |
137 | + alert("에러가 발생했습니다."); | |
138 | + } | |
139 | + console.error(error.message); | |
140 | + }; | |
141 | + }, | |
142 | + | |
143 | + // 개별 권한 업데이트 | |
144 | + updatePermission(index, permission, event) { | |
145 | + this.menuAuthorLists[index][permission] = event.target.checked ? 'Y' : 'N'; | |
146 | + }, | |
147 | + | |
148 | + // 전체 선택/해제 | |
149 | + toggleAll(index) { | |
150 | + const item = this.menuAuthorLists[index]; | |
151 | + const allChecked = this.isAllChecked(item); | |
152 | + const newValue = allChecked ? 'N' : 'Y'; | |
153 | + | |
154 | + // 모든 권한을 동일하게 설정 | |
155 | + item.redng = newValue; | |
156 | + item.write = newValue; | |
157 | + item.updt = newValue; | |
158 | + item.delete = newValue; | |
159 | + }, | |
160 | + | |
161 | + // 전체 선택 상태 확인 (모든 권한이 'Y'인지 체크) | |
162 | + isAllChecked(item) { | |
163 | + return item.redng === 'Y' && item.write === 'Y' && item.updt === 'Y' && item.delete === 'Y'; | |
164 | + }, | |
165 | + | |
166 | + // 수정 | |
167 | + async fnUpdate() { | |
168 | + try { | |
169 | + let data = []; | |
170 | + for (let menuAuthor of this.menuAuthorLists) { | |
171 | + data.push({ | |
172 | + authorCode: menuAuthor.authorCode, | |
173 | + menuId: menuAuthor.menuId, | |
174 | + redng: menuAuthor.redng, | |
175 | + write: menuAuthor.write, | |
176 | + updt: menuAuthor.updt, | |
177 | + delete: menuAuthor.delete, | |
178 | + }) | |
179 | + } | |
180 | + | |
181 | + const response = await updateMenuAuthorsProc(data); | |
182 | + const result = response.data.data; | |
183 | + | |
184 | + alert("수정되었습니다."); | |
185 | + | |
186 | + this.findMenuAuthorList(this.selectedAuthor); // 목록 조회 | |
187 | + } catch (error) { | |
188 | + if (error.response) { | |
189 | + alert(error.response.data.message); | |
190 | + } else { | |
191 | + alert("에러가 발생했습니다."); | |
192 | + } | |
193 | + console.error(error.message); | |
194 | + }; | |
195 | + }, | |
196 | + } | |
197 | +} | |
198 | +</script> | |
199 | +<style scoped> | |
200 | +tr { | |
201 | + cursor: pointer; | |
202 | +} | |
203 | + | |
204 | +.tbl-wrap #myTable .selected { | |
205 | + color: #FFFFFF; | |
206 | + background-color: #213F9A; | |
207 | +} | |
208 | +</style>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/Manager/system/accessControlManagement.vue
... | ... | @@ -1,224 +0,0 @@ |
1 | -<template> | |
2 | - <div class="card "> | |
3 | - <div class="card-body "> | |
4 | - <h2 class="card-title">접근제어관리</h2> | |
5 | - <div class="flex align-top"> | |
6 | - <div class="sch-form-wrap search"> | |
7 | - | |
8 | - <div class="tbl-wrap table-scroll"> | |
9 | - <table id="myTable" class="tbl data"> | |
10 | - <!-- 동적으로 <th> 생성 --> | |
11 | - <thead> | |
12 | - <tr> | |
13 | - <th>권한목록 </th> | |
14 | - </tr> | |
15 | - </thead> | |
16 | - <!-- 동적으로 <td> 생성 --> | |
17 | - <tbody> | |
18 | - <tr v-for="(item, index) in listData" :key="index"> | |
19 | - <td></td> | |
20 | - </tr> | |
21 | - </tbody> | |
22 | - </table> | |
23 | - | |
24 | - </div> | |
25 | - </div> | |
26 | - | |
27 | - <div style="width: 100%;"> | |
28 | - <div class="tbl-wrap chk-area"> | |
29 | - <table id="myTable" class="tbl data"> | |
30 | - | |
31 | - <thead> | |
32 | - <tr> | |
33 | - <th>메뉴명</th> | |
34 | - <th>전체</th> | |
35 | - <th>읽기</th> | |
36 | - <th>쓰기</th> | |
37 | - <th>수정</th> | |
38 | - <th>삭제</th> | |
39 | - </tr> | |
40 | - </thead> | |
41 | - <!-- 동적으로 <td> 생성 --> | |
42 | - <tbody> | |
43 | - <tr v-for="(item, index) in listData" :key="index"> | |
44 | - <td>{{ item.menuName }}</td> | |
45 | - <td> | |
46 | - <div class="form-check"> | |
47 | - <input | |
48 | - type="checkbox" | |
49 | - :id="`all_${index}`" | |
50 | - v-model="item.permissions.all" | |
51 | - @change="toggleAll(index)" | |
52 | - /> | |
53 | - <label :for="`all_${index}`"></label> | |
54 | - </div> | |
55 | - </td> | |
56 | - <td> | |
57 | - <div class="form-check"> | |
58 | - <input | |
59 | - type="checkbox" | |
60 | - :id="`read_${index}`" | |
61 | - v-model="item.permissions.read" | |
62 | - /> | |
63 | - <label :for="`read_${index}`"></label> | |
64 | - </div> | |
65 | - </td> | |
66 | - <td> | |
67 | - <div class="form-check"> | |
68 | - <input | |
69 | - type="checkbox" | |
70 | - :id="`write_${index}`" | |
71 | - v-model="item.permissions.write" | |
72 | - /> | |
73 | - <label :for="`write_${index}`"></label> | |
74 | - </div> | |
75 | - </td> | |
76 | - <td> | |
77 | - <div class="form-check"> | |
78 | - <input | |
79 | - type="checkbox" | |
80 | - :id="`edit_${index}`" | |
81 | - v-model="item.permissions.edit" | |
82 | - /> | |
83 | - <label :for="`edit_${index}`"></label> | |
84 | - </div> | |
85 | - </td> | |
86 | - <td> | |
87 | - <div class="form-check"> | |
88 | - <input | |
89 | - type="checkbox" | |
90 | - :id="`delete_${index}`" | |
91 | - v-model="item.permissions.delete" | |
92 | - /> | |
93 | - <label :for="`delete_${index}`"></label> | |
94 | - </div> | |
95 | - </td> | |
96 | - </tr> | |
97 | - </tbody> | |
98 | - </table> | |
99 | - | |
100 | - </div> | |
101 | - </div> | |
102 | - </div> | |
103 | - </div> | |
104 | - | |
105 | - </div> | |
106 | - | |
107 | -</template> | |
108 | - | |
109 | -<script> | |
110 | -import GoogleCalendar from "../../../component/GoogleCalendar.vue" | |
111 | -import { SearchOutlined } from '@ant-design/icons-vue'; | |
112 | -export default { | |
113 | - data() { | |
114 | - return { | |
115 | - require: "/client/resources/img/require.png", | |
116 | - h3icon: "/client/resources/img/h3icon.png", | |
117 | - photoicon: "/client/resources/img/photo_icon.png", | |
118 | - img1: "/client/resources/img/img.png", | |
119 | - icon1: "/client/resources/img/icon.png", | |
120 | - dateicon: "/client/resources/img/date.png", | |
121 | - startbtn: "/client/resources/img/start.png", | |
122 | - stopbtn: "/client/resources/img/stop.png", | |
123 | - moreicon: "/client/resources/img/more.png", | |
124 | - today: new Date().toLocaleDateString('ko-KR', { | |
125 | - year: 'numeric', | |
126 | - month: '2-digit', | |
127 | - day: '2-digit', | |
128 | - weekday: 'short', | |
129 | - }), | |
130 | - time: this.getCurrentTime(), | |
131 | - listData: [ | |
132 | - { | |
133 | - menuName: '메뉴1', | |
134 | - permissions: { | |
135 | - all: false, | |
136 | - read: false, | |
137 | - write: false, | |
138 | - edit: false, | |
139 | - delete: false, | |
140 | - }, | |
141 | - }, | |
142 | - { | |
143 | - menuName: '메뉴2', | |
144 | - permissions: { | |
145 | - all: false, | |
146 | - read: false, | |
147 | - write: false, | |
148 | - edit: false, | |
149 | - delete: false, | |
150 | - }, | |
151 | - }, | |
152 | - ] | |
153 | - } | |
154 | - }, | |
155 | - components: { | |
156 | - SearchOutlined | |
157 | - }, | |
158 | - methods: { | |
159 | - toggleAll(index) { | |
160 | - const all = this.listData[index].permissions.all; | |
161 | - this.listData[index].permissions.read = all; | |
162 | - this.listData[index].permissions.write = all; | |
163 | - this.listData[index].permissions.edit = all; | |
164 | - this.listData[index].permissions.delete = all; | |
165 | - }, | |
166 | - formatBudget(amount) { | |
167 | - return new Intl.NumberFormat().format(amount) + ' 원'; | |
168 | - }, | |
169 | - isPastPeriod(period) { | |
170 | - // 예: '2025-05-01 ~ 2025-05-03' → 종료일 추출 | |
171 | - const endDateStr = period.split('~')[1]?.trim(); | |
172 | - if (!endDateStr) return false; | |
173 | - | |
174 | - const endDate = new Date(endDateStr); | |
175 | - const today = new Date(); | |
176 | - | |
177 | - // 현재 날짜보다 과거면 true | |
178 | - return endDate < today; | |
179 | - }, | |
180 | - getStatusClass(status) { | |
181 | - return status === 'active' ? 'status-active' : 'status-inactive'; | |
182 | - }, | |
183 | - getStatusClass(status) { | |
184 | - if (status === '미진행') return 'status-pending'; | |
185 | - if (status === '진행중') return 'status-approved'; | |
186 | - | |
187 | - // Default empty string | |
188 | - return ''; | |
189 | - }, | |
190 | - getCurrentTime() { | |
191 | - const now = new Date(); | |
192 | - const hours = String(now.getHours()).padStart(2, '0'); | |
193 | - const minutes = String(now.getMinutes()).padStart(2, '0'); | |
194 | - const seconds = String(now.getSeconds()).padStart(2, '0'); | |
195 | - return `${hours}:${minutes}:${seconds}`; | |
196 | - }, | |
197 | - getCategoryClass(category) { | |
198 | - switch (category) { | |
199 | - case '용역': return 'category-service'; | |
200 | - case '내부': return 'category-internal'; | |
201 | - case '국가과제': return 'category-government'; | |
202 | - default: return ''; | |
203 | - } | |
204 | - }, | |
205 | - }, | |
206 | - watch: { | |
207 | - | |
208 | - }, | |
209 | - computed: { | |
210 | - | |
211 | - }, | |
212 | - mounted() { | |
213 | - console.log('main mounted'); | |
214 | - setInterval(() => { | |
215 | - this.time = this.getCurrentTime(); | |
216 | - }, 1000); | |
217 | - } | |
218 | -} | |
219 | -</script> | |
220 | -<style scoped> | |
221 | -tr { | |
222 | - cursor: pointer; | |
223 | -} | |
224 | -</style>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/Manager/system/system.vue
... | ... | @@ -1,87 +0,0 @@ |
1 | -<template> | |
2 | - <div class="sidemenu"> | |
3 | - <div class="myinfo simple"> | |
4 | - <div class="name-box"> | |
5 | - <div class="img-area"> | |
6 | - <div><img :src="photoicon" alt=""> | |
7 | - <p class="name">OOO과장</p> | |
8 | - </div> | |
9 | - <div class="info"> | |
10 | - <p>솔루션 개발팀</p> | |
11 | - <i class="fa-bars"></i> | |
12 | - <p>팀장</p> | |
13 | - </div> | |
14 | - </div> | |
15 | - </div> | |
16 | - | |
17 | - | |
18 | - <ul class="menu-box danil"> | |
19 | - <router-link :to="{ name: 'userManagement' }" exact-active-class="active-link" v-slot="{ isExactActive }"> | |
20 | - <li><p>사용자권한관리</p> | |
21 | - <div class="icon"><img :src="menuicon" alt=""></div></li> | |
22 | - </router-link> | |
23 | - <router-link :to="{ name: 'accessControlManagement' }" exact-active-class="active-link" v-slot="{ isExactActive }"> | |
24 | - <li> | |
25 | - <p>접근제어관리</p> | |
26 | - <div class="icon"><img :src="menuicon" alt=""></div> | |
27 | - </li> | |
28 | - </router-link> | |
29 | - <router-link :to="{ name: 'commonCodeManagement' }" exact-active-class="active-link" v-slot="{ isExactActive }"> | |
30 | - <li> | |
31 | - <p>공통코드관리</p> | |
32 | - <div class="icon"><img :src="menuicon" alt=""></div> | |
33 | - </li> | |
34 | - </router-link> | |
35 | - | |
36 | - | |
37 | - </ul> | |
38 | - | |
39 | - | |
40 | - </div> | |
41 | - </div> | |
42 | - <!-- End Page Title --> | |
43 | - <div class="content"> | |
44 | - <router-view></router-view> | |
45 | - | |
46 | - </div> | |
47 | -</template> | |
48 | - | |
49 | -<script> | |
50 | -import { ref } from 'vue'; | |
51 | - | |
52 | -export default { | |
53 | - data() { | |
54 | - return { | |
55 | - photoicon: "/client/resources/img/photo_icon.png", | |
56 | - menuicon: "/client/resources/img/menuicon2.png", | |
57 | - topmenuicon: "/client/resources/img/topmenuicon.png", | |
58 | - // 데이터 초기화 | |
59 | - years: [2023, 2024, 2025], // 연도 목록 | |
60 | - months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], // 월 목록 | |
61 | - selectedYear: '', | |
62 | - selectedMonth: '', | |
63 | - DeptData: [ | |
64 | - { member: '', deptNM: '', acceptTerms: false }, | |
65 | - // 더 많은 데이터 추가... | |
66 | - ], | |
67 | - filteredData: [], | |
68 | - }; | |
69 | - }, | |
70 | - computed: { | |
71 | - }, | |
72 | - methods: { | |
73 | - | |
74 | - // 페이지 변경 | |
75 | - changePage(page) { | |
76 | - this.currentPage = page; | |
77 | - }, | |
78 | - }, | |
79 | - created() { | |
80 | - }, | |
81 | - mounted() { | |
82 | - | |
83 | - }, | |
84 | -}; | |
85 | -</script> | |
86 | - | |
87 | -<style scoped></style> |
--- client/views/pages/Manager/system/userManagement.vue
... | ... | @@ -1,176 +0,0 @@ |
1 | -<template> | |
2 | - <div class="card "> | |
3 | - <div class="card-body "> | |
4 | - <h2 class="card-title">사용자권한관리</h2> | |
5 | - <div class="flex align-top"> | |
6 | - <div class="sch-form-wrap search"> | |
7 | - | |
8 | - <div class="tbl-wrap table-scroll"> | |
9 | - <table id="myTable" class="tbl data"> | |
10 | - <!-- 동적으로 <th> 생성 --> | |
11 | - <thead> | |
12 | - <tr> | |
13 | - <th>권한목록 </th> | |
14 | - </tr> | |
15 | - </thead> | |
16 | - <!-- 동적으로 <td> 생성 --> | |
17 | - <tbody> | |
18 | - <tr v-for="(item, index) in listData" :key="index"> | |
19 | - <td></td> | |
20 | - </tr> | |
21 | - </tbody> | |
22 | - </table> | |
23 | - | |
24 | - </div> | |
25 | - </div> | |
26 | - | |
27 | - <div style="width: 100%;"> | |
28 | - <div class=" sch-form-wrap title-wrap"> | |
29 | - <h3><img :src="h3icon" alt="">권한 정보</h3> | |
30 | - <div class="buttons" style="margin: 0;"> | |
31 | - <button type="submit" class="btn sm sm tertiary">신규</button> | |
32 | - <button type="reset" class="btn sm sm secondary">등록</button> | |
33 | - <button type="delete" class="btn sm sm btn-red">삭제</button> | |
34 | - </div> | |
35 | - </div> | |
36 | - <form class="row g-3 pt-3 needs-validation detail" @submit.prevent="handleSubmit" | |
37 | - style="margin-bottom: 3rem;"> | |
38 | - <div class="col-12"> | |
39 | - <label for="purpose" class="form-label"> | |
40 | - <p>권한코드 | |
41 | - <p class="require"><img :src="require" alt=""></p> | |
42 | - </p> | |
43 | - </label> | |
44 | - <input type="text" class="form-control" id="purpose" v-model="purpose" /> | |
45 | - </div> | |
46 | - <div class="col-12"> | |
47 | - <label for="purpose" class="form-label"> | |
48 | - <p>권한명 | |
49 | - <p class="require"><img :src="require" alt=""></p> | |
50 | - </p> | |
51 | - </label> | |
52 | - <input type="text" class="form-control" id="purpose" v-model="purpose" /> | |
53 | - </div> | |
54 | - | |
55 | - <div class="col-12 chuljang "> | |
56 | - <label for="prvonsh" class="form-label">권한설명</label> | |
57 | - <input type="text" class="form-control textarea" id="reason" v-model="reason" /> | |
58 | - </div> | |
59 | - <div class="col-12 border-x input-radio"> | |
60 | - <label for="prvonsh" class="form-label"> <p>사용여부 | |
61 | - <p class="require"><img :src="require" alt=""></p> | |
62 | - </p></label> | |
63 | - <div class="chk-area"> | |
64 | - <div class="form-check"> | |
65 | - <input type="radio" name="rdo_1" id="rdo_1"> | |
66 | - <label for="rdo_1">사용</label> | |
67 | - </div> | |
68 | - <div class="form-check"> | |
69 | - <input type="radio" name="rdo_1" id="rdo_2" checked> | |
70 | - <label for="rdo_2">미사용</label> | |
71 | - </div> | |
72 | - </div> | |
73 | - </div> | |
74 | - | |
75 | - | |
76 | - </form> | |
77 | - </div> | |
78 | - </div> | |
79 | - </div> | |
80 | - | |
81 | - </div> | |
82 | - | |
83 | -</template> | |
84 | - | |
85 | -<script> | |
86 | -import GoogleCalendar from "../../../component/GoogleCalendar.vue" | |
87 | -import { SearchOutlined } from '@ant-design/icons-vue'; | |
88 | -export default { | |
89 | - data() { | |
90 | - return { | |
91 | - require: "/client/resources/img/require.png", | |
92 | - h3icon: "/client/resources/img/h3icon.png", | |
93 | - photoicon: "/client/resources/img/photo_icon.png", | |
94 | - img1: "/client/resources/img/img.png", | |
95 | - icon1: "/client/resources/img/icon.png", | |
96 | - dateicon: "/client/resources/img/date.png", | |
97 | - startbtn: "/client/resources/img/start.png", | |
98 | - stopbtn: "/client/resources/img/stop.png", | |
99 | - moreicon: "/client/resources/img/more.png", | |
100 | - today: new Date().toLocaleDateString('ko-KR', { | |
101 | - year: 'numeric', | |
102 | - month: '2-digit', | |
103 | - day: '2-digit', | |
104 | - weekday: 'short', | |
105 | - }), | |
106 | - time: this.getCurrentTime(), | |
107 | - listData: Array.from({ length: 20 }, (_, i) => ({ | |
108 | - department: `부서 ${i + 1}`, | |
109 | - name: `이름 ${i + 1}`, | |
110 | - position: `직급 ${i + 1}` | |
111 | - })) | |
112 | - } | |
113 | - }, | |
114 | - components: { | |
115 | - SearchOutlined | |
116 | - }, | |
117 | - methods: { | |
118 | - formatBudget(amount) { | |
119 | - return new Intl.NumberFormat().format(amount) + ' 원'; | |
120 | - }, | |
121 | - isPastPeriod(period) { | |
122 | - // 예: '2025-05-01 ~ 2025-05-03' → 종료일 추출 | |
123 | - const endDateStr = period.split('~')[1]?.trim(); | |
124 | - if (!endDateStr) return false; | |
125 | - | |
126 | - const endDate = new Date(endDateStr); | |
127 | - const today = new Date(); | |
128 | - | |
129 | - // 현재 날짜보다 과거면 true | |
130 | - return endDate < today; | |
131 | - }, | |
132 | - getStatusClass(status) { | |
133 | - return status === 'active' ? 'status-active' : 'status-inactive'; | |
134 | - }, | |
135 | - getStatusClass(status) { | |
136 | - if (status === '미진행') return 'status-pending'; | |
137 | - if (status === '진행중') return 'status-approved'; | |
138 | - | |
139 | - // Default empty string | |
140 | - return ''; | |
141 | - }, | |
142 | - getCurrentTime() { | |
143 | - const now = new Date(); | |
144 | - const hours = String(now.getHours()).padStart(2, '0'); | |
145 | - const minutes = String(now.getMinutes()).padStart(2, '0'); | |
146 | - const seconds = String(now.getSeconds()).padStart(2, '0'); | |
147 | - return `${hours}:${minutes}:${seconds}`; | |
148 | - }, | |
149 | - getCategoryClass(category) { | |
150 | - switch (category) { | |
151 | - case '용역': return 'category-service'; | |
152 | - case '내부': return 'category-internal'; | |
153 | - case '국가과제': return 'category-government'; | |
154 | - default: return ''; | |
155 | - } | |
156 | - }, | |
157 | - }, | |
158 | - watch: { | |
159 | - | |
160 | - }, | |
161 | - computed: { | |
162 | - | |
163 | - }, | |
164 | - mounted() { | |
165 | - console.log('main mounted'); | |
166 | - setInterval(() => { | |
167 | - this.time = this.getCurrentTime(); | |
168 | - }, 1000); | |
169 | - } | |
170 | -} | |
171 | -</script> | |
172 | -<style scoped> | |
173 | -tr { | |
174 | - cursor: pointer; | |
175 | -} | |
176 | -</style>(파일 끝에 줄바꿈 문자 없음) |
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?