
--- client/resources/css/reset.css
+++ client/resources/css/reset.css
... | ... | @@ -82,6 +82,17 @@ |
82 | 82 |
border: 1px solid #d8d3c7; |
83 | 83 |
} |
84 | 84 |
|
85 |
+input::-webkit-outer-spin-button, |
|
86 |
+input::-webkit-inner-spin-button { |
|
87 |
+ -webkit-appearance: none; |
|
88 |
+ margin: 0; |
|
89 |
+} |
|
90 |
+ |
|
91 |
+/* Firefox */ |
|
92 |
+input[type=number] { |
|
93 |
+ -moz-appearance: textfield; |
|
94 |
+} |
|
95 |
+ |
|
85 | 96 |
input[type="button"]{ |
86 | 97 |
width: 100%; |
87 | 98 |
background: none; |
... | ... | @@ -90,9 +101,11 @@ |
90 | 101 |
} |
91 | 102 |
|
92 | 103 |
select{ |
93 |
- width: 32%; |
|
104 |
+ /* width: 32%; */ |
|
105 |
+ width: 100%; |
|
94 | 106 |
border-radius: 0.5rem; |
95 | 107 |
border: 1px solid #d8d3c7; |
108 |
+ padding: 1rem; |
|
96 | 109 |
} |
97 | 110 |
|
98 | 111 |
select:last-child{ |
... | ... | @@ -108,4 +121,15 @@ |
108 | 121 |
textarea{ |
109 | 122 |
width: 100%; |
110 | 123 |
height: 150px; |
111 |
-}(파일 끝에 줄바꿈 문자 없음) |
|
124 |
+} |
|
125 |
+ |
|
126 |
+a { |
|
127 |
+ cursor: pointer; |
|
128 |
+} |
|
129 |
+ |
|
130 |
+a.active { |
|
131 |
+ color: #0089ff; |
|
132 |
+ font-weight: bold; |
|
133 |
+ font-size: 1.1em; |
|
134 |
+} |
|
135 |
+ |
+++ client/resources/js/CommonUtil.js
... | ... | @@ -0,0 +1,507 @@ |
1 | +/** | |
2 | + * @author 최정우 | |
3 | + | |
4 | + * @since 2019.12.06 | |
5 | + * | |
6 | + * 공통 자바스크립트 Util입니다. | |
7 | + */ | |
8 | + | |
9 | +const CommonUtil = (function () { | |
10 | + | |
11 | + var _utils = { | |
12 | + /** | |
13 | + * 빈 객체 여부 | |
14 | + */ | |
15 | + isEmpty: function (data) { | |
16 | + if (data === undefined || data === null || data === "" || data.length === 0 || (data.constructor == Object && Object.keys(data).length === 0)) { | |
17 | + if ((typeof data) === "number") { | |
18 | + return false | |
19 | + } else { | |
20 | + return true; | |
21 | + } | |
22 | + } else { | |
23 | + return false; | |
24 | + } | |
25 | + }, | |
26 | + | |
27 | + /** | |
28 | + * empty to null | |
29 | + */ | |
30 | + toNull: function (data) { | |
31 | + if(data === undefined || data === "") { | |
32 | + try { | |
33 | + data = null; | |
34 | + return data; | |
35 | + } catch (e) { | |
36 | + console.log("commonUtil.js - empty to null convert error : ", e); | |
37 | + return data; | |
38 | + } | |
39 | + } else { | |
40 | + return data; | |
41 | + } | |
42 | + }, | |
43 | + | |
44 | + /** | |
45 | + * string to JSON | |
46 | + */ | |
47 | + toJson: function (data) { | |
48 | + if ("string" === (typeof data)) { | |
49 | + try { | |
50 | + return JSON.parse(data); | |
51 | + } catch (e) { | |
52 | + console.log("commonUtil.js - string to json convert error : ", e); | |
53 | + return data; | |
54 | + } | |
55 | + } else { | |
56 | + return data; | |
57 | + } | |
58 | + }, | |
59 | + | |
60 | + /** | |
61 | + * string to JSON | |
62 | + */ | |
63 | + toJson: function (data) { | |
64 | + if ("string" === (typeof data)) { | |
65 | + try { | |
66 | + return JSON.parse(data); | |
67 | + } catch (e) { | |
68 | + console.log("commonUtil.js - string to json convert error : ", e); | |
69 | + return data; | |
70 | + } | |
71 | + } else { | |
72 | + return data; | |
73 | + } | |
74 | + }, | |
75 | + | |
76 | + /** | |
77 | + * JSON to string | |
78 | + */ | |
79 | + toString: function (data) { | |
80 | + try { | |
81 | + return JSON.parse(data); | |
82 | + } catch (e) { | |
83 | + console.log("commonUtil.js - json to string convert error : ", e); | |
84 | + return data; | |
85 | + } | |
86 | + }, | |
87 | + | |
88 | + /** | |
89 | + * 다중 separator split | |
90 | + */ | |
91 | + split: function (text, separator) { | |
92 | + var words = []; | |
93 | + if (this.isEmpty(text) == false && this.isEmpty(separator) == false && separator.length > 0) { | |
94 | + words.push(text); | |
95 | + for (var i = 0; i < separator.length; i++) { | |
96 | + var subWords = []; | |
97 | + for (var j = 0; j < words.length; j++) { | |
98 | + if (this.isEmpty(words[j]) == false && this.isEmpty(separator[i]) == false) { | |
99 | + subWords = subWords.concat(words[j].split(separator[i])); | |
100 | + } else { | |
101 | + if (words[j] == false) { | |
102 | + subWords.push(words[j]); | |
103 | + } else { | |
104 | + continue; | |
105 | + } | |
106 | + } | |
107 | + } | |
108 | + words = subWords; | |
109 | + } | |
110 | + return words; | |
111 | + } else { | |
112 | + if (this.isEmpty(text) == false) { | |
113 | + words.push(text); | |
114 | + } | |
115 | + return words; | |
116 | + } | |
117 | + }, | |
118 | + | |
119 | + /** | |
120 | + * 객체 깊은 복사 | |
121 | + */ | |
122 | + copyObject: function (obj) { | |
123 | + if (obj === null || typeof(obj) !== 'object') return obj; | |
124 | + | |
125 | + try { | |
126 | + return JSON.parse(JSON.stringify(obj)); | |
127 | + } catch (e) { | |
128 | + console.log("commonUtil.js - copyObject error : ", e); | |
129 | + return null; | |
130 | + } | |
131 | + }, | |
132 | + /** | |
133 | + * 날짜 + 시간 구하기 | |
134 | + * | |
135 | + * | |
136 | + | |
137 | + */ | |
138 | + getDateTime : function () { | |
139 | + return this.getDate()+ " " + this.getFullTime(); | |
140 | + }, | |
141 | + | |
142 | + /** | |
143 | + * 날짜 구하기 | |
144 | + * | |
145 | + * param 설명 | |
146 | + * | |
147 | + * options = { | |
148 | + * addYear(Integer), | |
149 | + * addMonth(Integer), | |
150 | + * addDay(Integer), | |
151 | + * separator(String) | |
152 | + * } | |
153 | + */ | |
154 | + getDate: function (options) { | |
155 | + | |
156 | + if (this.isEmpty(options) == true) { | |
157 | + options = { | |
158 | + addYear: 0, | |
159 | + addMonth: 0, | |
160 | + addDay: 0, | |
161 | + separator: '-' | |
162 | + } | |
163 | + } else { | |
164 | + options.addYear = options.addYear || 0; | |
165 | + options.addMonth = options.addMonth || 0; | |
166 | + options.addDay = options.addDay || 0; | |
167 | + options.separator = options.separator || '-'; | |
168 | + } | |
169 | + | |
170 | + var date = new Date(); | |
171 | + date.setFullYear(date.getFullYear() + options.addYear); | |
172 | + date.setMonth(date.getMonth() + options.addMonth); | |
173 | + date.setDate(date.getDate() + options.addDay); | |
174 | + | |
175 | + var yyyy = date.getFullYear(); | |
176 | + var mm = date.getMonth() + 1; | |
177 | + var dd = date.getDate(); | |
178 | + | |
179 | + return yyyy + options.separator + this.prefixZero(mm, 2) + options.separator + this.prefixZero(dd, 2); | |
180 | + }, | |
181 | + | |
182 | + /** | |
183 | + * 현재 년도 조회 | |
184 | + */ | |
185 | + getYear: function () { | |
186 | + var date = new Date(); | |
187 | + return date.getFullYear(); | |
188 | + }, | |
189 | + | |
190 | + /** | |
191 | + * 현재 월 조회 | |
192 | + */ | |
193 | + getMonth: function () { | |
194 | + var date = new Date(); | |
195 | + return date.getMonth() + 1; | |
196 | + }, | |
197 | + | |
198 | + /** | |
199 | + * 현재 월 조회 | |
200 | + */ | |
201 | + getFullMonth: function () { | |
202 | + var date = new Date(); | |
203 | + return this.prefixZero((date.getMonth() + 1), 2); | |
204 | + }, | |
205 | + | |
206 | + /** | |
207 | + * 현재 일 조회 | |
208 | + */ | |
209 | + getDay: function () { | |
210 | + var date = new Date(); | |
211 | + return date.getDate(); | |
212 | + }, | |
213 | + | |
214 | + /** | |
215 | + * 현재 일 조회 | |
216 | + */ | |
217 | + getFullDay: function () { | |
218 | + var date = new Date(); | |
219 | + return this.prefixZero(date.getDate(), 2); | |
220 | + }, | |
221 | + | |
222 | + /** | |
223 | + * 현재 시간 조회 | |
224 | + */ | |
225 | + getHour: function () { | |
226 | + var date = new Date(); | |
227 | + return date.getFullYear(); | |
228 | + }, | |
229 | + | |
230 | + /** | |
231 | + * 현재 분 조회 | |
232 | + */ | |
233 | + getMinute: function () { | |
234 | + var date = new Date(); | |
235 | + return date.getMinutes() + 1; | |
236 | + }, | |
237 | + | |
238 | + /** | |
239 | + * 현재 초 조회 | |
240 | + */ | |
241 | + getSeconds: function () { | |
242 | + var date = new Date(); | |
243 | + return date.getSeconds(); | |
244 | + }, | |
245 | + | |
246 | + /** | |
247 | + * 시간 구하기 | |
248 | + * | |
249 | + * param 설명 | |
250 | + * | |
251 | + * options = { | |
252 | + * addHour(Integer), | |
253 | + * addMinute(Integer), | |
254 | + * addSeconds(Integer), | |
255 | + * separator(String) | |
256 | + * } | |
257 | + */ | |
258 | + getFullTime: function (options) { | |
259 | + if (this.isEmpty(options) == true) { | |
260 | + options = { | |
261 | + addHour: 0, | |
262 | + addMinute: 0, | |
263 | + addSeconds: 0, | |
264 | + separator: '-' | |
265 | + } | |
266 | + } else { | |
267 | + options.addHour = options.addHour || 0; | |
268 | + options.addMinute = options.addMinute || 0; | |
269 | + options.addSeconds = options.addSeconds || 0; | |
270 | + options.separator = options.separator || ':'; | |
271 | + } | |
272 | + | |
273 | + var date = new Date(); | |
274 | + date.setHours(date.getHours() + options.addHour); | |
275 | + date.setMinutes(date.getMinutes() + options.addMinute); | |
276 | + date.setSeconds(date.getSeconds() + options.addSeconds); | |
277 | + | |
278 | + var h = date.getHours(); | |
279 | + var m = date.getMinutes(); | |
280 | + var s = date.getSeconds(); | |
281 | + | |
282 | + return this.prefixZero(h, 2) + ":" + this.prefixZero(m, 2) + ":" + this.prefixZero(s, 2); | |
283 | + }, | |
284 | + | |
285 | + /** | |
286 | + * 시간 구하기 | |
287 | + * | |
288 | + * param 설명 | |
289 | + * | |
290 | + * options = { | |
291 | + * addHour(Integer), | |
292 | + * addMinute(Integer), | |
293 | + * separator(String) | |
294 | + * } | |
295 | + */ | |
296 | + getTime: function (options) { | |
297 | + if (this.isEmpty(options) == true) { | |
298 | + options = { | |
299 | + addHour: 0, | |
300 | + addMinute: 0, | |
301 | + separator: '-' | |
302 | + } | |
303 | + } else { | |
304 | + options.addHour = options.addHour || 0; | |
305 | + options.addMinute = options.addMinute || 0; | |
306 | + options.separator = options.separator || ':'; | |
307 | + } | |
308 | + | |
309 | + var date = new Date(); | |
310 | + date.setHours(date.getHours() + options.addHour); | |
311 | + date.setMinutes(date.getMinutes() + options.addMinute); | |
312 | + | |
313 | + var h = date.getHours(); | |
314 | + var m = date.getMinutes(); | |
315 | + | |
316 | + return this.prefixZero(h, 2) + ":" + this.prefixZero(m, 2); | |
317 | + }, | |
318 | + | |
319 | + /** | |
320 | + * 특정 길이만큼 앞에'0' 붙이기 | |
321 | + * | |
322 | + * param 설명 | |
323 | + * | |
324 | + * text(String or Integer): 맨 뒤에 붙일 문자열(숫자든 문자든 상관웞음) | |
325 | + * length(Integer): 해당 값 만큼 '0'을 붙임 (단, text의 문자열 길이를 뺌) | |
326 | + * ex) this.prefixZero(2, 5) => 00002, this.prefixZero(20, 5) => 00020 | |
327 | + * | |
328 | + */ | |
329 | + prefixZero: function (text, length) { | |
330 | + var zero = ''; | |
331 | + var suffix = text; | |
332 | + | |
333 | + if ((typeof text) === "number") { | |
334 | + suffix = text.toString(); | |
335 | + } | |
336 | + | |
337 | + | |
338 | + if (suffix.length < length) { | |
339 | + for (let i = 0; i < length - suffix.length; i++) { | |
340 | + zero += '0'; | |
341 | + } | |
342 | + } | |
343 | + return zero + suffix; | |
344 | + }, | |
345 | + | |
346 | + /** | |
347 | + * Date => text | |
348 | + */ | |
349 | + dateToText: function (date) { | |
350 | + var d = new Date(date); | |
351 | + var yyyy = d.getFullYear(); | |
352 | + var mm = d.getMonth() + 1; | |
353 | + var dd = d.getDate(); | |
354 | + return yyyy + "-" + this.prefixZero(mm, 2) + "-" + this.prefixZero(dd, 2); | |
355 | + }, | |
356 | + | |
357 | + /** | |
358 | + * 최솟값은 포함, 최댓값은 제외한 정수 난수 생성(최솟값 ~ 최댓값 - 1) | |
359 | + * | |
360 | + * param 설명 | |
361 | + * | |
362 | + * min(Integer): 난수 생성시, 최소값 | |
363 | + * max(Integer): 난수 생성시, 최대값 | |
364 | + * | |
365 | + * ex) getRandomInt(2, 5) => 2~5사이의 정수 난수 값 리턴 | |
366 | + */ | |
367 | + getRandomInt: function (min, max) { | |
368 | + min = Math.ceil(min); | |
369 | + max = Math.floor(max); | |
370 | + return Math.floor(Math.random() * (max - min)) + min; | |
371 | + }, | |
372 | + | |
373 | + /** | |
374 | + * 현재 시스템의 URL 조회 | |
375 | + * | |
376 | + * ex) http://localohst:8080, https://www.naver.com | |
377 | + */ | |
378 | + getSystemURL: function () { | |
379 | + var url = window.location.protocol | |
380 | + + "//" + window.location.host; | |
381 | + return url; | |
382 | + }, | |
383 | + | |
384 | + /** | |
385 | + * 현재 시스템의 URL 경로 조회 | |
386 | + * | |
387 | + * ex) http://localohst:8080/dataset/datasetPostList => /dataset/datasetPostList | |
388 | + */ | |
389 | + getSystemPath: function () { | |
390 | + var path = window.location.pathname; | |
391 | + return path; | |
392 | + }, | |
393 | + | |
394 | + /** | |
395 | + * 3글자 마다 콤마 찍기 (돈) | |
396 | + * | |
397 | + * ex) 10000 => 10,000 | |
398 | + */ | |
399 | + comma: function (text) { | |
400 | + try { | |
401 | + return text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); | |
402 | + } catch (e) { | |
403 | + if (this.isEmpty(text) == true) { | |
404 | + return "-"; | |
405 | + } else { | |
406 | + return text; | |
407 | + } | |
408 | + } | |
409 | + }, | |
410 | + | |
411 | + /** | |
412 | + * 3글자 마다 콤마 찍기 (돈) | |
413 | + * | |
414 | + * ex) 10,000 => 10000 | |
415 | + */ | |
416 | + removeComma: function (text) { | |
417 | + try { | |
418 | + return text.toString().replace(/,/g, "");; | |
419 | + } catch (e) { | |
420 | + if (this.isEmpty(text) == true) { | |
421 | + return "-"; | |
422 | + } else { | |
423 | + return text; | |
424 | + } | |
425 | + } | |
426 | + }, | |
427 | + | |
428 | + /** | |
429 | + * json 데이터 가지고 오기 (외부 JSON 파일 PATH or URL) (동기 요청) | |
430 | + */ | |
431 | + getJsonByPromise: function (url, isAsync) { | |
432 | + if (this.isEmpty(url) == true) { | |
433 | + new Error('COMMON_UTIL - getJson(url, isAsync) Error : url(parameter) is empty') | |
434 | + } | |
435 | + if (this.isEmpty(isAsync) == true) { | |
436 | + isAsync = true; | |
437 | + } | |
438 | + | |
439 | + return new Promise(function (resolve, reject) { | |
440 | + var xhr = new XMLHttpRequest(); | |
441 | + xhr.onload = function (e) { | |
442 | + if (xhr.readyState === 4) { | |
443 | + if (xhr.status === 200) { | |
444 | + resolve(JSON.parse(this.responseText)); | |
445 | + } else { | |
446 | + reject(this); | |
447 | + } | |
448 | + } | |
449 | + }; | |
450 | + xhr.onerror = function (e) { | |
451 | + reject(this); | |
452 | + }; | |
453 | + xhr.open("GET", url, isAsync); | |
454 | + //xhr.responseType='json'; | |
455 | + xhr.send(null); | |
456 | + }); | |
457 | + }, | |
458 | + | |
459 | + /** | |
460 | + * json 데이터 가지고 오기 (동기 요청) (외부 JSON 파일 PATH or URL) | |
461 | + */ | |
462 | + getJsonBySync: function (url) { | |
463 | + var result = {}; | |
464 | + if (this.isEmpty(url) == true) { | |
465 | + new Error('COMMON_UTIL - getJson(url, isAsync) Error : url(parameter) is empty') | |
466 | + return result; | |
467 | + } | |
468 | + | |
469 | + var xhr = new XMLHttpRequest(); | |
470 | + xhr.onload = function (e) { | |
471 | + if (xhr.readyState === 4) { | |
472 | + if (xhr.status === 200) { | |
473 | + result = JSON.parse(this.responseText); | |
474 | + } else { | |
475 | + console.error(this); | |
476 | + } | |
477 | + } | |
478 | + }; | |
479 | + xhr.onerror = function (e) { | |
480 | + console.error(this); | |
481 | + }; | |
482 | + xhr.open("GET", url, false); | |
483 | + xhr.send(null); | |
484 | + | |
485 | + return result; | |
486 | + }, | |
487 | + | |
488 | + } | |
489 | + | |
490 | + | |
491 | + //초기화 | |
492 | + function init() { | |
493 | + //console.info('commonUtil.js initialized.'); | |
494 | + return _utils; | |
495 | + } | |
496 | + | |
497 | + | |
498 | + return init(); | |
499 | + | |
500 | +})(); | |
501 | + | |
502 | + | |
503 | +export default CommonUtil; | |
504 | + | |
505 | + | |
506 | + | |
507 | + |
--- client/views/component/Category.jsx
+++ client/views/component/Category.jsx
... | ... | @@ -2,11 +2,14 @@ |
2 | 2 |
import Button from "./Button.jsx"; |
3 | 3 |
|
4 | 4 |
function Menu({ className, children, href, title }) { |
5 |
+ console.log(`Menu - className : ${className}, children : ${children}`); |
|
6 |
+ |
|
7 |
+ |
|
5 | 8 |
if (!children) { |
6 | 9 |
return <li className="venue-lvl"> |
7 | 10 |
<a href={href ?? '#'}> |
8 | 11 |
<span>{title}</span> |
9 |
- <Button className={"btn-more-small gray-btn margin-left"} btnName={"삭제"} /> |
|
12 |
+ <button className={"btn-more-small gray-btn margin-left"} onClick={()=> {}}>삭제</button> |
|
10 | 13 |
</a> |
11 | 14 |
</li> |
12 | 15 |
} |
... | ... | @@ -18,7 +21,7 @@ |
18 | 21 |
return <li className={className}> |
19 | 22 |
<a href={href ?? '#'} onClick={() => setOpend(open ? '' : 'open')} className="max-agency"> |
20 | 23 |
<span>{title}</span> |
21 |
- <Button className={"btn-more-small red-btn margin-left"} btnName={"추가"} /> |
|
24 |
+ <button className={"btn-more-small red-btn margin-left"} onClick={()=> {}}>추가</button> |
|
22 | 25 |
</a> |
23 | 26 |
{open && <ul id="venue-scope-options"> |
24 | 27 |
{children} |
--- client/views/component/Modal_Guardian.jsx
+++ client/views/component/Modal_Guardian.jsx
... | ... | @@ -5,372 +5,80 @@ |
5 | 5 |
import Pagination from "./Pagination.jsx"; |
6 | 6 |
|
7 | 7 |
|
8 |
-export default function Modal_Guardian({ open, close, header, useSeniorId }) { |
|
9 |
- |
|
10 |
- const seniorId = useSeniorId; |
|
11 |
- //대상자 - 보호자 매칭 리스트 |
|
12 |
- const [sgMatchList, setSgMatchList] = React.useState([]); |
|
13 |
- const [guardianList, setGuardianList] = React.useState([]); |
|
14 |
- const [addGuardian, setAddGuardian] = React.useState(true); //추가된 보호자가 있는지 확인 |
|
15 |
- |
|
16 |
- //사용자 등록 초기값 설정 |
|
17 |
- const [userName, setUserName] = React.useState(""); |
|
18 |
- const [gender, setGender] = React.useState(""); |
|
19 |
- const [brith, setBrith] = React.useState(""); |
|
20 |
- const [telNum, setTelNum] = React.useState(""); |
|
21 |
- const [homeAddress, setHomeAddress] = React.useState(""); |
|
22 |
- const [relationship, setRelationship] = React.useState(""); |
|
23 |
- const [guardianId, setGuardianId] = React.useState(""); |
|
24 |
- |
|
25 |
- //-------- 페이징 작업 설정 시작 --------// |
|
26 |
- const limit = 5; // 페이지당 보여줄 공지 개수 |
|
27 |
- const [page, setPage] = React.useState(1); //page index |
|
28 |
- const offset = (page - 1) * limit; //게시물 위치 계산 |
|
29 |
- const [guardianTotal, setGuardianTotal] = React.useState(0); //최대길이 넣을 변수 |
|
30 |
- |
|
31 |
- //-------- 변경되는 데이터 Handler 설정 --------// |
|
32 |
- const handleUserName = (e) => { |
|
33 |
- e.target.value = e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, ''); |
|
34 |
- setUserName(e.target.value); |
|
35 |
- }; |
|
36 |
- const handleBrithday = (e) => { |
|
37 |
- setBrith(e.target.value); |
|
38 |
- }; |
|
39 |
- const handleTelNum = (e) => { |
|
40 |
- e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`); |
|
41 |
- setTelNum(e.target.value); |
|
42 |
- }; |
|
43 |
- const handelRelationship = (e) => { |
|
44 |
- setRelationship(e.target.value); |
|
45 |
- }; |
|
46 |
- const handleGuarianId = (e) => { |
|
47 |
- setGuardianId(e.target.value); |
|
48 |
- }; |
|
49 |
- |
|
50 |
- // 데이터 초기화 함수 |
|
51 |
- const dataReset = () => { |
|
52 |
- setGuardianId(""); |
|
53 |
- setUserName(""); |
|
54 |
- setBrith(""); |
|
55 |
- setTelNum(""); |
|
56 |
- setRelationship(""); |
|
57 |
- } |
|
58 |
- // 매칭 리스트 출력 영역 |
|
59 |
- const getSelectMatchList = () => { |
|
60 |
- fetch("/user/selectSeniorGuardianMatch.json", { |
|
61 |
- method: "POST", |
|
62 |
- headers: { |
|
63 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
64 |
- }, |
|
65 |
- body: JSON.stringify({ |
|
66 |
- senior_id: seniorId, |
|
67 |
- viewPage : "matchView", |
|
68 |
- }), |
|
69 |
- }).then((response) => response.json()).then((data) => { |
|
70 |
- console.log("getSelectMatchList : ", data); |
|
71 |
- setSgMatchList(data); |
|
72 |
- setGuardianTotal(data.length); |
|
73 |
- setAddGuardian(false); |
|
74 |
- }).catch((error) => { |
|
75 |
- console.log('getSelectMatchList() /user/selectSeniorGuardianMatch.json error : ', error); |
|
76 |
- }); |
|
77 |
- }; |
|
78 |
- |
|
79 |
- // 보호자 리스트 불러오기 |
|
80 |
- const getSelectGuardianList = () => { |
|
81 |
- fetch("/user/selectUserList.json", { |
|
82 |
- method: "POST", |
|
83 |
- headers: { |
|
84 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
85 |
- }, |
|
86 |
- body: JSON.stringify({ |
|
87 |
- agency_id: 'AGENCY01', |
|
88 |
- authority: 'GUARDIAN01', |
|
89 |
- }), |
|
90 |
- }).then((response) => response.json()).then((data) => { |
|
91 |
- const rowData = data; |
|
92 |
- setGuardianList(rowData) |
|
93 |
- |
|
94 |
- }).catch((error) => { |
|
95 |
- console.log('getSelectSeniorList() /user/selectUserList.json error : ', error); |
|
96 |
- }); |
|
97 |
- }; |
|
98 |
- |
|
99 |
- // 보호자 등록 영역 |
|
100 |
- const insertUser = () => { |
|
101 |
- if (userName == "") { |
|
102 |
- alert("이름을 입력해 주세요."); |
|
103 |
- return; |
|
104 |
- } else if (brith == "") { |
|
105 |
- alert("생년월일을 선택해 주세요."); |
|
106 |
- return; |
|
107 |
- } else if (telNum == "") { |
|
108 |
- alert("연락처를 입력해 선택해 주세요."); |
|
109 |
- return; |
|
110 |
- } |
|
111 |
- var insertBtn = confirm("등록하시겠습니까?"); |
|
112 |
- if (insertBtn) { |
|
113 |
- fetch("/user/insertUserData.json", { |
|
114 |
- method: "POST", |
|
115 |
- headers: { |
|
116 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
117 |
- }, |
|
118 |
- body: JSON.stringify({ |
|
119 |
- user_name: userName, |
|
120 |
- user_gender: gender != "" ? gender : null, |
|
121 |
- user_birth: brith, |
|
122 |
- user_phonenumber: telNum, |
|
123 |
- user_address: homeAddress != "" ? homeAddress : null, |
|
124 |
- agency_id: 'AGENCY01', |
|
125 |
- government_id: 'GOVERNMENT01', |
|
126 |
- authority: 'GUARDIAN01', |
|
127 |
- |
|
128 |
- }), |
|
129 |
- }).then((response) => response.json()).then((data) => { |
|
130 |
- console.log("보호자 등록"); |
|
131 |
- insertGuadian(); |
|
132 |
- }).catch((error) => { |
|
133 |
- console.log('insertUser() /user/insertUserData.json error : ', error); |
|
134 |
- }); |
|
135 |
- } else { |
|
136 |
- return; |
|
137 |
- } |
|
138 |
- } |
|
139 |
- const insertGuadian = () => { |
|
140 |
- fetch("/user/insertGuardian.json", { |
|
141 |
- method: "POST", |
|
142 |
- headers: { |
|
143 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
144 |
- }, |
|
145 |
- body: JSON.stringify({ |
|
146 |
- user_phonenumber: telNum, |
|
147 |
- }), |
|
148 |
- }).then((response) => response.json()).then((data) => { |
|
149 |
- console.log("보호자 테이블 데이터 등록"); |
|
150 |
- matchSeniorGuadian2(); |
|
151 |
- }).catch((error) => { |
|
152 |
- console.log('insertGuadian() /user/insertGuardian.json error : ', error); |
|
153 |
- }); |
|
154 |
- }; |
|
155 |
- |
|
156 |
- const matchSeniorGuadian = () => { |
|
157 |
- fetch("/user/insertSeniorGuardianMatch.json", { |
|
158 |
- method: "POST", |
|
159 |
- headers: { |
|
160 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
161 |
- }, |
|
162 |
- body: JSON.stringify({ |
|
163 |
- senior_id: seniorId, |
|
164 |
- guardian_id: guardianId, |
|
165 |
- senior_relationship: relationship, |
|
166 |
- }), |
|
167 |
- }).then((response) => response.json()).then((data) => { |
|
168 |
- console.log("매칭 등록"); |
|
169 |
- dataReset(); |
|
170 |
- setAddGuardian(true); |
|
171 |
- }).catch((error) => { |
|
172 |
- console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error); |
|
173 |
- }); |
|
174 |
- }; |
|
175 |
- |
|
176 |
- const matchSeniorGuadian2 = () => { |
|
177 |
- fetch("/user/insertSeniorGuardianMatch.json", { |
|
178 |
- method: "POST", |
|
179 |
- headers: { |
|
180 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
181 |
- }, |
|
182 |
- body: JSON.stringify({ |
|
183 |
- senior_id: seniorId, |
|
184 |
- user_phonenumber: telNum, |
|
185 |
- senior_relationship: relationship, |
|
186 |
- }), |
|
187 |
- }).then((response) => response.json()).then((data) => { |
|
188 |
- console.log("매칭 등록"); |
|
189 |
- dataReset(); |
|
190 |
- setAddGuardian(true); |
|
191 |
- }).catch((error) => { |
|
192 |
- console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error); |
|
193 |
- }); |
|
194 |
- }; |
|
195 |
- |
|
196 |
- // 시니어 보호자 매칭 제거 |
|
197 |
- const updateSeniorGuardianMatch = (guardian_id) => { |
|
198 |
- let insertBtn = confirm("삭제하시겠습니까?"); |
|
199 |
- if (insertBtn) { |
|
200 |
- fetch("/user/updateGuardianMatchEnd.json", { |
|
201 |
- method: "POST", |
|
202 |
- headers: { |
|
203 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
204 |
- }, |
|
205 |
- body: JSON.stringify({ |
|
206 |
- senior_id: seniorId, |
|
207 |
- guardian_id: guardian_id, |
|
208 |
- endMatch: "matchDel", |
|
209 |
- }), |
|
210 |
- }).then((response) => response.json()).then((data) => { |
|
211 |
- alert('삭제되었습니다.'); |
|
212 |
- setAddGuardian(true); |
|
213 |
- }).catch((error) => { |
|
214 |
- console.log('updateSeniorGuardianMatch() /user/updateGuardianMatchEnd.json error : ', error); |
|
215 |
- }); |
|
216 |
- } else { |
|
217 |
- return; |
|
218 |
- } |
|
219 |
- } |
|
220 |
- |
|
221 |
- // 보호자 등록페이지 데이터 |
|
222 |
- const thead = [ |
|
223 |
- "No", |
|
224 |
- "이름", |
|
225 |
- "생년월일", |
|
226 |
- "연락처", |
|
227 |
- "대상자와의 관계", |
|
228 |
- "삭제" |
|
229 |
- ]; |
|
230 |
- const key = [ |
|
231 |
- "rn", |
|
232 |
- "guardian_name", |
|
233 |
- "user_birth", |
|
234 |
- "user_phonenumber", |
|
235 |
- "senior_relationship", |
|
236 |
- ]; |
|
237 |
- |
|
238 |
- React.useEffect(() => { |
|
239 |
- getSelectGuardianList(); |
|
240 |
- getSelectMatchList(); |
|
241 |
- }, [addGuardian]) |
|
8 |
+export default function Modal_Guardian({ open, close, seniorId }) { |
|
242 | 9 |
|
243 | 10 |
return ( |
244 | 11 |
<div class={open ? "openModal modal" : "modal"}> |
245 | 12 |
{open ? ( |
246 | 13 |
<div className="modal-inner"> |
247 | 14 |
<div className="modal-header flex"> |
248 |
- {header} |
|
249 |
- <Button className={"close"} onClick={close} btnName={"X"} /> |
|
15 |
+ 보호자(가족) 보기 |
|
16 |
+ <button className={"close"} onClick={() => {close()}}>X</button> |
|
250 | 17 |
</div> |
251 | 18 |
<div className="modal-main"> |
252 | 19 |
<div className="board-wrap"> |
253 |
- <SubTitle explanation={"이미 등록된 사용자는 기존 ID,PW를 사용하시면 됩니다."} className="margin-bottom" /> |
|
254 |
- <table className="margin-bottom2 senior-insert"> |
|
255 |
- <tr> |
|
256 |
- <th>검색</th> |
|
257 |
- <input type="text" list="protectorlist" value={guardianId} onChange={handleGuarianId} /> |
|
258 |
- <datalist id="protectorlist"> |
|
259 |
- {/* <option value="가족1(ID)"></option> |
|
260 |
- <option value="가족2(ID)"></option> */} |
|
261 |
- {guardianList.map((item) => { |
|
262 |
- // console.log('item : ',item) |
|
263 |
- // setGaudianId(item['user_id']) |
|
264 |
- // setTelNum(item['user_phonenumber']) |
|
265 |
- return <option value={item['user_id']}>{item['user_name']}({item['user_id']})</option> |
|
266 |
- })} |
|
267 |
- </datalist> |
|
268 |
- </tr> |
|
269 |
- <tr> |
|
270 |
- <th>대상자와의 관계</th> |
|
271 |
- <td colSpan={3}> |
|
272 |
- <input type="text" value={relationship} onChange={handelRelationship} /> |
|
273 |
- </td> |
|
274 |
- </tr> |
|
275 |
- </table> |
|
276 |
- <div className="btn-wrap flex-center margin-bottom5"> |
|
277 |
- <Button |
|
278 |
- className={"btn-small green-btn"} |
|
279 |
- btnName={"등록"} |
|
280 |
- onClick={() => { |
|
281 |
- matchSeniorGuadian(); |
|
282 |
- }} |
|
283 |
- /> |
|
20 |
+ |
|
21 |
+ <SubTitle explanation={"OOO님의 보호자(가족)"} className="margin-bottom" /> |
|
22 |
+ <div> |
|
23 |
+ <table className='caregiver-user'> |
|
24 |
+ <thead> |
|
25 |
+ <tr> |
|
26 |
+ <th>No</th> |
|
27 |
+ <th>이름</th> |
|
28 |
+ <th>대상자와의 관계</th> |
|
29 |
+ <th>연락처</th> |
|
30 |
+ <th>생년월일</th> |
|
31 |
+ <th>삭제</th> |
|
32 |
+ </tr> |
|
33 |
+ </thead> |
|
34 |
+ <tbody> |
|
35 |
+ <tr> |
|
36 |
+ <td>No</td> |
|
37 |
+ <td>이름</td> |
|
38 |
+ <td>대상자와의 관계</td> |
|
39 |
+ <td>연락처</td> |
|
40 |
+ <td>생년월일</td> |
|
41 |
+ <td><button className={"btn-small gray-btn"} onClick={() => {}}>삭제</button></td> |
|
42 |
+ </tr> |
|
43 |
+ </tbody> |
|
44 |
+ </table> |
|
284 | 45 |
</div> |
46 |
+ <div> |
|
47 |
+ {/* <Pagination total={guardianTotal} limit={limit} page={page} setPage={setPage} /> */} |
|
48 |
+ </div> |
|
49 |
+ |
|
50 |
+ |
|
285 | 51 |
<SubTitle explanation={"최초 ID는 연락처, PW는 생년월일 8자리입니다."} className="margin-bottom" /> |
286 | 52 |
<table className="margin-bottom2 senior-insert"> |
287 | 53 |
<tr> |
288 | 54 |
<th><span style={{color : "red"}}>*</span>이름</th> |
289 | 55 |
<td> |
290 |
- <input type="text" value={userName} onChange={handleUserName} /> |
|
56 |
+ <input type="text"/> |
|
291 | 57 |
</td> |
292 | 58 |
<th><span style={{color : "red"}}>*</span>생년월일</th> |
293 | 59 |
<td> |
294 | 60 |
<div className="flex"> |
295 |
- <input type='date' value={brith} onChange={handleBrithday} /> |
|
61 |
+ <input type='date' /> |
|
296 | 62 |
</div> |
297 | 63 |
</td> |
298 | 64 |
</tr> |
299 | 65 |
<tr> |
300 | 66 |
<th><span style={{color : "red"}}>*</span>연락처</th> |
301 | 67 |
<td colSpan={3}> |
302 |
- <input type="input" maxLength="13" value={telNum} onChange={handleTelNum} /> |
|
68 |
+ <input type="input" maxLength="13" /> |
|
303 | 69 |
</td> |
304 | 70 |
</tr> |
305 | 71 |
<tr> |
306 | 72 |
<th>대상자와의 관계</th> |
307 | 73 |
<td colSpan={3}> |
308 |
- <input type="text" value={relationship} onChange={handelRelationship} /> |
|
74 |
+ <input type="text" /> |
|
309 | 75 |
</td> |
310 | 76 |
</tr> |
311 | 77 |
</table> |
312 | 78 |
<div className="btn-wrap flex-center margin-bottom5"> |
313 |
- <Button |
|
314 |
- className={"btn-small green-btn"} |
|
315 |
- btnName={"추가"} |
|
316 |
- onClick={() => { |
|
317 |
- insertUser() |
|
318 |
- }} |
|
319 |
- /> |
|
79 |
+ <button className={"btn-small green-btn"} onClick={() => {}}>추가</button> |
|
320 | 80 |
</div> |
321 |
- <div> |
|
322 |
- {/* <Table |
|
323 |
- className={"caregiver-user"} |
|
324 |
- head={thead3} |
|
325 |
- contents={sgMatchList} |
|
326 |
- contentKey={key3} |
|
327 |
- view={"guadianMatch"} |
|
328 |
- offset={offset} |
|
329 |
- limit={limit} |
|
330 |
- /> */} |
|
331 |
- <table className='caregiver-user'> |
|
332 |
- <thead> |
|
333 |
- <tr> |
|
334 |
- {thead.map((i) => { |
|
335 |
- return <th>{i}</th>; |
|
336 |
- })} |
|
337 |
- </tr> |
|
338 |
- </thead> |
|
339 |
- <tbody> |
|
340 |
- {sgMatchList.slice(offset, offset + limit).map((i, index) => { |
|
341 |
- const guardian_id = i.guardian_id; |
|
342 |
- return ( |
|
343 |
- <tr key={index}> |
|
344 |
- {key.map((kes) => { |
|
345 |
- return ( |
|
346 |
- <> |
|
347 |
- <td |
|
348 |
- onClick={() => { |
|
349 |
- console.log("i.guardian_id : ", i.guardian_id); |
|
350 |
- }}> |
|
351 |
- {i[kes]} |
|
352 |
- </td> |
|
353 |
- </> |
|
354 |
- ); |
|
355 |
- })} |
|
356 |
- <td> |
|
357 |
- <Button |
|
358 |
- className={"btn-small gray-btn"} |
|
359 |
- btnName={"삭제"} |
|
360 |
- onClick={() => { |
|
361 |
- updateSeniorGuardianMatch(guardian_id); |
|
362 |
- }} |
|
363 |
- /> |
|
364 |
- </td> |
|
365 |
- </tr> |
|
366 |
- ); |
|
367 |
- })} |
|
368 |
- </tbody> |
|
369 |
- </table> |
|
370 |
- </div> |
|
371 |
- <div> |
|
372 |
- <Pagination total={guardianTotal} limit={limit} page={page} setPage={setPage} /> |
|
373 |
- </div> |
|
81 |
+ |
|
374 | 82 |
</div> |
375 | 83 |
</div> |
376 | 84 |
</div> |
+++ client/views/component/Modal_Guardian_back_230329.jsx
... | ... | @@ -0,0 +1,381 @@ |
1 | +import React from "react"; | |
2 | +import Button from "./Button.jsx"; | |
3 | +import SubTitle from "./SubTitle.jsx"; | |
4 | +import Table from "./Table.jsx"; | |
5 | +import Pagination from "./Pagination.jsx"; | |
6 | + | |
7 | + | |
8 | +export default function Modal_Guardian({ open, close, header, useSeniorId }) { | |
9 | + | |
10 | + const seniorId = useSeniorId; | |
11 | + //대상자 - 보호자 매칭 리스트 | |
12 | + const [sgMatchList, setSgMatchList] = React.useState([]); | |
13 | + const [guardianList, setGuardianList] = React.useState([]); | |
14 | + const [addGuardian, setAddGuardian] = React.useState(true); //추가된 보호자가 있는지 확인 | |
15 | + | |
16 | + //사용자 등록 초기값 설정 | |
17 | + const [userName, setUserName] = React.useState(""); | |
18 | + const [gender, setGender] = React.useState(""); | |
19 | + const [brith, setBrith] = React.useState(""); | |
20 | + const [telNum, setTelNum] = React.useState(""); | |
21 | + const [homeAddress, setHomeAddress] = React.useState(""); | |
22 | + const [relationship, setRelationship] = React.useState(""); | |
23 | + const [guardianId, setGuardianId] = React.useState(""); | |
24 | + | |
25 | + //-------- 페이징 작업 설정 시작 --------// | |
26 | + const limit = 5; // 페이지당 보여줄 공지 개수 | |
27 | + const [page, setPage] = React.useState(1); //page index | |
28 | + const offset = (page - 1) * limit; //게시물 위치 계산 | |
29 | + const [guardianTotal, setGuardianTotal] = React.useState(0); //최대길이 넣을 변수 | |
30 | + | |
31 | + //-------- 변경되는 데이터 Handler 설정 --------// | |
32 | + const handleUserName = (e) => { | |
33 | + e.target.value = e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, ''); | |
34 | + setUserName(e.target.value); | |
35 | + }; | |
36 | + const handleBrithday = (e) => { | |
37 | + setBrith(e.target.value); | |
38 | + }; | |
39 | + const handleTelNum = (e) => { | |
40 | + e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`); | |
41 | + setTelNum(e.target.value); | |
42 | + }; | |
43 | + const handelRelationship = (e) => { | |
44 | + setRelationship(e.target.value); | |
45 | + }; | |
46 | + const handleGuarianId = (e) => { | |
47 | + setGuardianId(e.target.value); | |
48 | + }; | |
49 | + | |
50 | + // 데이터 초기화 함수 | |
51 | + const dataReset = () => { | |
52 | + setGuardianId(""); | |
53 | + setUserName(""); | |
54 | + setBrith(""); | |
55 | + setTelNum(""); | |
56 | + setRelationship(""); | |
57 | + } | |
58 | + // 매칭 리스트 출력 영역 | |
59 | + const getSelectMatchList = () => { | |
60 | + fetch("/user/selectSeniorGuardianMatch.json", { | |
61 | + method: "POST", | |
62 | + headers: { | |
63 | + 'Content-Type': 'application/json; charset=UTF-8' | |
64 | + }, | |
65 | + body: JSON.stringify({ | |
66 | + senior_id: seniorId, | |
67 | + viewPage : "matchView", | |
68 | + }), | |
69 | + }).then((response) => response.json()).then((data) => { | |
70 | + console.log("getSelectMatchList : ", data); | |
71 | + setSgMatchList(data); | |
72 | + setGuardianTotal(data.length); | |
73 | + setAddGuardian(false); | |
74 | + }).catch((error) => { | |
75 | + console.log('getSelectMatchList() /user/selectSeniorGuardianMatch.json error : ', error); | |
76 | + }); | |
77 | + }; | |
78 | + | |
79 | + // 보호자 리스트 불러오기 | |
80 | + const getSelectGuardianList = () => { | |
81 | + fetch("/user/selectUserList.json", { | |
82 | + method: "POST", | |
83 | + headers: { | |
84 | + 'Content-Type': 'application/json; charset=UTF-8' | |
85 | + }, | |
86 | + body: JSON.stringify({ | |
87 | + agency_id: 'AGENCY01', | |
88 | + authority: 'GUARDIAN01', | |
89 | + }), | |
90 | + }).then((response) => response.json()).then((data) => { | |
91 | + const rowData = data; | |
92 | + setGuardianList(rowData) | |
93 | + | |
94 | + }).catch((error) => { | |
95 | + console.log('getSelectSeniorList() /user/selectUserList.json error : ', error); | |
96 | + }); | |
97 | + }; | |
98 | + | |
99 | + // 보호자 등록 영역 | |
100 | + const insertUser = () => { | |
101 | + if (userName == "") { | |
102 | + alert("이름을 입력해 주세요."); | |
103 | + return; | |
104 | + } else if (brith == "") { | |
105 | + alert("생년월일을 선택해 주세요."); | |
106 | + return; | |
107 | + } else if (telNum == "") { | |
108 | + alert("연락처를 입력해 선택해 주세요."); | |
109 | + return; | |
110 | + } | |
111 | + var insertBtn = confirm("등록하시겠습니까?"); | |
112 | + if (insertBtn) { | |
113 | + fetch("/user/insertUserData.json", { | |
114 | + method: "POST", | |
115 | + headers: { | |
116 | + 'Content-Type': 'application/json; charset=UTF-8' | |
117 | + }, | |
118 | + body: JSON.stringify({ | |
119 | + user_name: userName, | |
120 | + user_gender: gender != "" ? gender : null, | |
121 | + user_birth: brith, | |
122 | + user_phonenumber: telNum, | |
123 | + user_address: homeAddress != "" ? homeAddress : null, | |
124 | + agency_id: 'AGENCY01', | |
125 | + government_id: 'GOVERNMENT01', | |
126 | + authority: 'GUARDIAN01', | |
127 | + | |
128 | + }), | |
129 | + }).then((response) => response.json()).then((data) => { | |
130 | + console.log("보호자 등록"); | |
131 | + insertGuadian(); | |
132 | + }).catch((error) => { | |
133 | + console.log('insertUser() /user/insertUserData.json error : ', error); | |
134 | + }); | |
135 | + } else { | |
136 | + return; | |
137 | + } | |
138 | + } | |
139 | + const insertGuadian = () => { | |
140 | + fetch("/user/insertGuardian.json", { | |
141 | + method: "POST", | |
142 | + headers: { | |
143 | + 'Content-Type': 'application/json; charset=UTF-8' | |
144 | + }, | |
145 | + body: JSON.stringify({ | |
146 | + user_phonenumber: telNum, | |
147 | + }), | |
148 | + }).then((response) => response.json()).then((data) => { | |
149 | + console.log("보호자 테이블 데이터 등록"); | |
150 | + matchSeniorGuadian2(); | |
151 | + }).catch((error) => { | |
152 | + console.log('insertGuadian() /user/insertGuardian.json error : ', error); | |
153 | + }); | |
154 | + }; | |
155 | + | |
156 | + const matchSeniorGuadian = () => { | |
157 | + fetch("/user/insertSeniorGuardianMatch.json", { | |
158 | + method: "POST", | |
159 | + headers: { | |
160 | + 'Content-Type': 'application/json; charset=UTF-8' | |
161 | + }, | |
162 | + body: JSON.stringify({ | |
163 | + senior_id: seniorId, | |
164 | + guardian_id: guardianId, | |
165 | + senior_relationship: relationship, | |
166 | + }), | |
167 | + }).then((response) => response.json()).then((data) => { | |
168 | + console.log("매칭 등록"); | |
169 | + dataReset(); | |
170 | + setAddGuardian(true); | |
171 | + }).catch((error) => { | |
172 | + console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error); | |
173 | + }); | |
174 | + }; | |
175 | + | |
176 | + const matchSeniorGuadian2 = () => { | |
177 | + fetch("/user/insertSeniorGuardianMatch.json", { | |
178 | + method: "POST", | |
179 | + headers: { | |
180 | + 'Content-Type': 'application/json; charset=UTF-8' | |
181 | + }, | |
182 | + body: JSON.stringify({ | |
183 | + senior_id: seniorId, | |
184 | + user_phonenumber: telNum, | |
185 | + senior_relationship: relationship, | |
186 | + }), | |
187 | + }).then((response) => response.json()).then((data) => { | |
188 | + console.log("매칭 등록"); | |
189 | + dataReset(); | |
190 | + setAddGuardian(true); | |
191 | + }).catch((error) => { | |
192 | + console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error); | |
193 | + }); | |
194 | + }; | |
195 | + | |
196 | + // 시니어 보호자 매칭 제거 | |
197 | + const updateSeniorGuardianMatch = (guardian_id) => { | |
198 | + let insertBtn = confirm("삭제하시겠습니까?"); | |
199 | + if (insertBtn) { | |
200 | + fetch("/user/updateGuardianMatchEnd.json", { | |
201 | + method: "POST", | |
202 | + headers: { | |
203 | + 'Content-Type': 'application/json; charset=UTF-8' | |
204 | + }, | |
205 | + body: JSON.stringify({ | |
206 | + senior_id: seniorId, | |
207 | + guardian_id: guardian_id, | |
208 | + endMatch: "matchDel", | |
209 | + }), | |
210 | + }).then((response) => response.json()).then((data) => { | |
211 | + alert('삭제되었습니다.'); | |
212 | + setAddGuardian(true); | |
213 | + }).catch((error) => { | |
214 | + console.log('updateSeniorGuardianMatch() /user/updateGuardianMatchEnd.json error : ', error); | |
215 | + }); | |
216 | + } else { | |
217 | + return; | |
218 | + } | |
219 | + } | |
220 | + | |
221 | + // 보호자 등록페이지 데이터 | |
222 | + const thead = [ | |
223 | + "No", | |
224 | + "이름", | |
225 | + "생년월일", | |
226 | + "연락처", | |
227 | + "대상자와의 관계", | |
228 | + "삭제" | |
229 | + ]; | |
230 | + const key = [ | |
231 | + "rn", | |
232 | + "guardian_name", | |
233 | + "user_birth", | |
234 | + "user_phonenumber", | |
235 | + "senior_relationship", | |
236 | + ]; | |
237 | + | |
238 | + React.useEffect(() => { | |
239 | + getSelectGuardianList(); | |
240 | + getSelectMatchList(); | |
241 | + }, [addGuardian]) | |
242 | + | |
243 | + return ( | |
244 | + <div class={open ? "openModal modal" : "modal"}> | |
245 | + {open ? ( | |
246 | + <div className="modal-inner"> | |
247 | + <div className="modal-header flex"> | |
248 | + {header} | |
249 | + <Button className={"close"} onClick={close} btnName={"X"} /> | |
250 | + </div> | |
251 | + <div className="modal-main"> | |
252 | + <div className="board-wrap"> | |
253 | + <SubTitle explanation={"이미 등록된 사용자는 기존 ID,PW를 사용하시면 됩니다."} className="margin-bottom" /> | |
254 | + <table className="margin-bottom2 senior-insert"> | |
255 | + <tr> | |
256 | + <th>검색</th> | |
257 | + <input type="text" list="protectorlist" value={guardianId} onChange={handleGuarianId} /> | |
258 | + <datalist id="protectorlist"> | |
259 | + {/* <option value="가족1(ID)"></option> | |
260 | + <option value="가족2(ID)"></option> */} | |
261 | + {guardianList.map((item) => { | |
262 | + // console.log('item : ',item) | |
263 | + // setGaudianId(item['user_id']) | |
264 | + // setTelNum(item['user_phonenumber']) | |
265 | + return <option value={item['user_id']}>{item['user_name']}({item['user_id']})</option> | |
266 | + })} | |
267 | + </datalist> | |
268 | + </tr> | |
269 | + <tr> | |
270 | + <th>대상자와의 관계</th> | |
271 | + <td colSpan={3}> | |
272 | + <input type="text" value={relationship} onChange={handelRelationship} /> | |
273 | + </td> | |
274 | + </tr> | |
275 | + </table> | |
276 | + <div className="btn-wrap flex-center margin-bottom5"> | |
277 | + <Button | |
278 | + className={"btn-small green-btn"} | |
279 | + btnName={"등록"} | |
280 | + onClick={() => { | |
281 | + matchSeniorGuadian(); | |
282 | + }} | |
283 | + /> | |
284 | + </div> | |
285 | + <SubTitle explanation={"최초 ID는 연락처, PW는 생년월일 8자리입니다."} className="margin-bottom" /> | |
286 | + <table className="margin-bottom2 senior-insert"> | |
287 | + <tr> | |
288 | + <th><span style={{color : "red"}}>*</span>이름</th> | |
289 | + <td> | |
290 | + <input type="text" value={userName} onChange={handleUserName} /> | |
291 | + </td> | |
292 | + <th><span style={{color : "red"}}>*</span>생년월일</th> | |
293 | + <td> | |
294 | + <div className="flex"> | |
295 | + <input type='date' value={brith} onChange={handleBrithday} /> | |
296 | + </div> | |
297 | + </td> | |
298 | + </tr> | |
299 | + <tr> | |
300 | + <th><span style={{color : "red"}}>*</span>연락처</th> | |
301 | + <td colSpan={3}> | |
302 | + <input type="input" maxLength="13" value={telNum} onChange={handleTelNum} /> | |
303 | + </td> | |
304 | + </tr> | |
305 | + <tr> | |
306 | + <th>대상자와의 관계</th> | |
307 | + <td colSpan={3}> | |
308 | + <input type="text" value={relationship} onChange={handelRelationship} /> | |
309 | + </td> | |
310 | + </tr> | |
311 | + </table> | |
312 | + <div className="btn-wrap flex-center margin-bottom5"> | |
313 | + <Button | |
314 | + className={"btn-small green-btn"} | |
315 | + btnName={"추가"} | |
316 | + onClick={() => { | |
317 | + insertUser() | |
318 | + }} | |
319 | + /> | |
320 | + </div> | |
321 | + <div> | |
322 | + {/* <Table | |
323 | + className={"caregiver-user"} | |
324 | + head={thead3} | |
325 | + contents={sgMatchList} | |
326 | + contentKey={key3} | |
327 | + view={"guadianMatch"} | |
328 | + offset={offset} | |
329 | + limit={limit} | |
330 | + /> */} | |
331 | + <table className='caregiver-user'> | |
332 | + <thead> | |
333 | + <tr> | |
334 | + {thead.map((i) => { | |
335 | + return <th>{i}</th>; | |
336 | + })} | |
337 | + </tr> | |
338 | + </thead> | |
339 | + <tbody> | |
340 | + {sgMatchList.slice(offset, offset + limit).map((i, index) => { | |
341 | + const guardian_id = i.guardian_id; | |
342 | + return ( | |
343 | + <tr key={index}> | |
344 | + {key.map((kes) => { | |
345 | + return ( | |
346 | + <> | |
347 | + <td | |
348 | + onClick={() => { | |
349 | + console.log("i.guardian_id : ", i.guardian_id); | |
350 | + }}> | |
351 | + {i[kes]} | |
352 | + </td> | |
353 | + </> | |
354 | + ); | |
355 | + })} | |
356 | + <td> | |
357 | + <Button | |
358 | + className={"btn-small gray-btn"} | |
359 | + btnName={"삭제"} | |
360 | + onClick={() => { | |
361 | + updateSeniorGuardianMatch(guardian_id); | |
362 | + }} | |
363 | + /> | |
364 | + </td> | |
365 | + </tr> | |
366 | + ); | |
367 | + })} | |
368 | + </tbody> | |
369 | + </table> | |
370 | + </div> | |
371 | + <div> | |
372 | + <Pagination total={guardianTotal} limit={limit} page={page} setPage={setPage} /> | |
373 | + </div> | |
374 | + </div> | |
375 | + </div> | |
376 | + </div> | |
377 | + ) : null} | |
378 | + </div> | |
379 | + | |
380 | + ); | |
381 | +}(파일 끝에 줄바꿈 문자 없음) |
--- client/views/component/Modal_SeniorInsert.jsx
+++ client/views/component/Modal_SeniorInsert.jsx
... | ... | @@ -1,268 +1,357 @@ |
1 |
-import React from "react"; |
|
1 |
+import React, { useState, useRef } from "react"; |
|
2 |
+import { useSelector } from "react-redux"; |
|
2 | 3 |
import Button from "./Button.jsx"; |
3 | 4 |
import SubTitle from "./SubTitle.jsx"; |
4 | 5 |
|
5 |
-export default function Modal({ open, close, header, setModalOpen3, setAddSenior }) { |
|
6 |
- // 사용자 등록 시 초기값 세팅 |
|
7 |
- // const [seniorId, setSeniorId] = React.useState(""); |
|
8 |
- const [userName, setUserName] = React.useState(""); |
|
9 |
- const [gender, setGender] = React.useState(""); |
|
10 |
- const [brith, setBrith] = React.useState(""); |
|
11 |
- const [telNum, setTelNum] = React.useState(""); |
|
12 |
- const [homeAddress, setHomeAddress] = React.useState(""); |
|
13 |
- const [medicineM, setMedicineM] = React.useState(false); |
|
14 |
- const [medicineL, setMedicineL] = React.useState(false); |
|
15 |
- const [medicineD, setMedicineD] = React.useState(false); |
|
16 |
- const [medication, setMedication] = React.useState(""); |
|
17 |
- const [note, setNote] = React.useState(""); |
|
6 |
+import CommonUtil from "../../resources/js/CommonUtil.js"; |
|
18 | 7 |
|
19 |
- // //id blor 처리 진행 |
|
20 |
- // const inputRef = React.useRef(); |
|
21 |
- // const settingBlor = (e) => { |
|
22 |
- // inputRef.current.blur(); |
|
23 |
- // } |
|
8 |
+export default function Modal({ open, close, seniorInsertCallback, defaultAgencyId, defaultGovernmentId }) { |
|
24 | 9 |
|
25 |
- // 등록 후 초기화 진행 |
|
26 |
- const dataReset = () => { |
|
27 |
- // setSeniorId(""); |
|
28 |
- setUserName(""); |
|
29 |
- setGender(""); |
|
30 |
- setBrith(""); |
|
31 |
- setTelNum(""); |
|
32 |
- setHomeAddress(""); |
|
33 |
- setMedicineM(""); |
|
34 |
- setMedicineL(""); |
|
35 |
- setMedicineD(""); |
|
36 |
- setMedication(""); |
|
37 |
- setNote(""); |
|
38 |
- } |
|
39 |
- //-------- 변경되는 데이터 Handler 설정 --------// |
|
40 |
- // const handleUserId = (e) => { |
|
41 |
- // console.log(e.target.value); |
|
42 |
- // setSeniorId(e.target.value); |
|
43 |
- // }; |
|
44 |
- const handleUserName = (e) => { |
|
45 |
- e.target.value=e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, ''); |
|
46 |
- setUserName(e.target.value); |
|
47 |
- }; |
|
48 |
- const handleGender = (e) => { |
|
49 |
- setGender(e.target.value); |
|
50 |
- }; |
|
51 |
- const handleBrithday = (e) => { |
|
52 |
- setBrith(e.target.value); |
|
53 |
- }; |
|
54 |
- const handleTelNum = (e) => { |
|
55 |
- e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`); |
|
56 |
- setTelNum(e.target.value); |
|
57 |
- }; |
|
58 |
- const handleHomeAddress = (e) => { |
|
59 |
- setHomeAddress(e.target.value); |
|
60 |
- }; |
|
61 |
- const handleMedicineM = (e) => { |
|
62 |
- setMedicineM(e.target.checked); |
|
63 |
- }; |
|
64 |
- const handleMedicineL = (e) => { |
|
65 |
- setMedicineL(e.target.checked); |
|
66 |
- }; |
|
67 |
- const handleMedicineD = (e) => { |
|
68 |
- setMedicineD(e.target.checked); |
|
69 |
- }; |
|
70 |
- const handleMedication = (e) => { |
|
71 |
- setMedication(e.target.value); |
|
72 |
- }; |
|
73 |
- const handleNote = (e) => { |
|
74 |
- setNote(e.target.value); |
|
75 |
- }; |
|
10 |
+ //console.log(`seniorInsertModal - defaultGovernmentId:${defaultGovernmentId}, defaultAgencyId:${defaultAgencyId}`) |
|
76 | 11 |
|
77 |
- //-------- 등록 버튼 동작 수행 영역 시작 --------// |
|
78 |
- // 대상자 정보 등록을 위한 함수 |
|
79 |
- const InsertUserData = () => { |
|
80 |
- //-------- 유효성 체크 --------// |
|
81 |
- if(userName == ""){ |
|
82 |
- alert("이름을 입력해 주세요."); |
|
83 |
- return ; |
|
84 |
- } else if(gender == "") { |
|
85 |
- alert("성별을 선택해 주세요."); |
|
86 |
- return ; |
|
87 |
- } else if(brith == "") { |
|
88 |
- alert("생년월일을 선택해 주세요."); |
|
89 |
- return ; |
|
90 |
- } else if(telNum == "") { |
|
91 |
- alert("연락처를 입력해 선택해 주세요."); |
|
92 |
- return ; |
|
93 |
- } else if(homeAddress == "") { |
|
94 |
- alert("주소를 선택해 주세요."); |
|
95 |
- return ; |
|
96 |
- } |
|
97 |
- var insertBtn = confirm("등록하시겠습니까?"); |
|
98 |
- if (insertBtn) { |
|
99 |
- fetch("/user/insertUserData.json", { |
|
100 |
- method: "POST", |
|
101 |
- headers: { |
|
102 |
- 'Content-Type': 'application/json; charset=UTF-8' |
|
103 |
- }, |
|
104 |
- body: JSON.stringify({ |
|
105 |
- user_name: userName, |
|
106 |
- user_gender: gender, |
|
107 |
- user_birth: brith, |
|
108 |
- user_phonenumber: telNum, |
|
109 |
- user_address: homeAddress, |
|
110 |
- agency_id: 'AGENCY01', |
|
111 |
- government_id: 'GOVERNMENT01', |
|
112 |
- authority: 'SENIOR01', |
|
113 |
- }), |
|
114 |
- }).then((response) => response.json()).then((data) => { |
|
115 |
- console.log("대상자 정보 등록"); |
|
116 |
- InsertUserPillData(); |
|
117 |
- }).catch((error) => { |
|
118 |
- console.log('insertUserData() /user/insertUserData.json error : ', error); |
|
119 |
- }); |
|
120 |
- } else { |
|
121 |
- return; |
|
122 |
- } |
|
123 |
- }; |
|
124 |
- // 대상자 약 복용 정보 등록을 위한 함수 |
|
125 |
- const InsertUserPillData = () => { |
|
126 |
- fetch("/user/insertSeniorMadication.json", { |
|
12 |
+ /**** 기본 조회 데이터 (시작) ****/ |
|
13 |
+ //전역 변수 저장 객체 |
|
14 |
+ const state = useSelector((state) => {return state}); |
|
15 |
+ |
|
16 |
+ //기관 계층 구조 목록 |
|
17 |
+ const [orgListOfHierarchy, setOrgListOfHierarchy] = React.useState([]); |
|
18 |
+ //기관(관리, 시행) 계층 구조 목록 조회 |
|
19 |
+ const orgSelectListOfHierarchy = () => { |
|
20 |
+ fetch("/org/orgSelectListOfHierarchy.json", { |
|
127 | 21 |
method: "POST", |
128 | 22 |
headers: { |
129 | 23 |
'Content-Type': 'application/json; charset=UTF-8' |
130 | 24 |
}, |
131 |
- body: JSON.stringify({ |
|
132 |
- user_phonenumber: telNum, |
|
133 |
- breakfast_medication_check: medicineM, |
|
134 |
- lunch_medication_check: medicineL, |
|
135 |
- dinner_medication_check: medicineD, |
|
136 |
- medication_pill: medication, |
|
137 |
- senior_note: note, |
|
138 |
- }), |
|
25 |
+ body: JSON.stringify({}), |
|
139 | 26 |
}).then((response) => response.json()).then((data) => { |
140 |
- console.log("약 정보 등록"); |
|
141 |
- dataReset(); |
|
142 |
- setAddSenior(true) |
|
143 |
- alert("등록 되었습니다."); |
|
144 |
- noticeModalClose() |
|
145 |
- |
|
27 |
+ console.log("기관(관리, 시행) 계층 구조 목록 조회 : ", data); |
|
28 |
+ setOrgListOfHierarchy(data); |
|
146 | 29 |
}).catch((error) => { |
147 |
- console.log('InsertUserPillData() /user/insertSeniorMadication.json error : ', error); |
|
30 |
+ console.log('orgSelectListOfHierarchy() /org/orgSelectListOfHierarchy.json error : ', error); |
|
148 | 31 |
}); |
149 | 32 |
}; |
150 |
- //-------- 등록 버튼 동작 수행 영역 끝 --------/ |
|
151 |
- //-------- 모달 종료 --------> |
|
152 |
- const noticeModalClose = () => { |
|
153 |
- dataReset(); |
|
154 |
- setModalOpen3(false); |
|
155 |
- }; |
|
33 |
+ const getAgencyList = () => { |
|
34 |
+ const government = orgListOfHierarchy.find(item => item['government_id'] == senior['government_id']); |
|
35 |
+ if (CommonUtil.isEmpty(government) || CommonUtil.isEmpty(government['agencyList'])) { |
|
36 |
+ return []; |
|
37 |
+ } else { |
|
38 |
+ return government['agencyList']; |
|
39 |
+ } |
|
40 |
+ } |
|
41 |
+ |
|
42 |
+ const [medicationTimeCodeList, setMedicationTimeCodeList] = React.useState([]); |
|
43 |
+ //복약 시간 코드 목록 조회 |
|
44 |
+ const medicationTimeCodeSelectList = () => { |
|
45 |
+ fetch("/common/medicationTimeCodeSelectList.json", { |
|
46 |
+ method: "POST", |
|
47 |
+ headers: { |
|
48 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
49 |
+ }, |
|
50 |
+ body: JSON.stringify({}), |
|
51 |
+ }).then((response) => response.json()).then((data) => { |
|
52 |
+ console.log("복약 시간 코드 목록 조회 : ", data); |
|
53 |
+ setMedicationTimeCodeList(data); |
|
54 |
+ |
|
55 |
+ //시니어 복약 정보 미리 세팅 |
|
56 |
+ let newSenior = JSON.parse(JSON.stringify(senior)); |
|
57 |
+ for (let i = 0; i < data.length; i++) { |
|
58 |
+ newSenior['seniorMedicationList'].push(data[i]['medication_time_code']); |
|
59 |
+ } |
|
60 |
+ setSenior(newSenior); |
|
61 |
+ }).catch((error) => { |
|
62 |
+ console.log('medicationTimeCodeSelectList() /common/medicationTimeCodeSelectList.json error : ', error); |
|
63 |
+ }); |
|
64 |
+ } |
|
65 |
+ /**** 기본 조회 데이터 (종료) ****/ |
|
66 |
+ |
|
67 |
+ |
|
68 |
+ |
|
69 |
+ |
|
70 |
+ //등록할 시니어 정보 |
|
71 |
+ const [senior, setSenior] = useState({ |
|
72 |
+ 'user_id': null, |
|
73 |
+ 'user_name': null, |
|
74 |
+ 'user_password': null, |
|
75 |
+ 'user_phonenumber': null, |
|
76 |
+ 'user_birth': null, |
|
77 |
+ 'user_gender': null, |
|
78 |
+ 'user_address': null, |
|
79 |
+ 'user_email': null, |
|
80 |
+ 'authority': 'ROLE_SENIOR', |
|
81 |
+ 'agency_id': !defaultAgencyId ? state.loginUser['agency_id'] : defaultAgencyId, |
|
82 |
+ 'government_id': !defaultGovernmentId ? state.loginUser['government_id'] : defaultGovernmentId, |
|
83 |
+ |
|
84 |
+ 'senior_id': null, |
|
85 |
+ 'care_grade': null, |
|
86 |
+ 'medication_pill': null, |
|
87 |
+ 'underlie_disease': null, |
|
88 |
+ 'senior_note': null, |
|
89 |
+ |
|
90 |
+ 'seniorMedicationList': [], |
|
91 |
+ }); |
|
92 |
+ //console.log(`seniorInsertModal - senior:`, senior); |
|
93 |
+ |
|
94 |
+ //각 데이터별로 Dom 정보 담을 Ref 생성 |
|
95 |
+ const seniorRefInit = JSON.parse(JSON.stringify(senior)); |
|
96 |
+ seniorRefInit['user_gender'] = {}; |
|
97 |
+ const seniorRef = useRef(seniorRefInit); |
|
98 |
+ |
|
99 |
+ //등록할 시니어 정보 변경 |
|
100 |
+ const seniorValueChange = (targetKey, value) => { |
|
101 |
+ let newSenior = JSON.parse(JSON.stringify(senior)); |
|
102 |
+ newSenior[targetKey] = value; |
|
103 |
+ setSenior(newSenior); |
|
104 |
+ } |
|
105 |
+ //등록할 시니어의 관리기관 변경 |
|
106 |
+ const seniorGovernmentIdChange = (value) => { |
|
107 |
+ let newSenior = JSON.parse(JSON.stringify(senior)); |
|
108 |
+ if (CommonUtil.isEmpty(value) == true) { |
|
109 |
+ newSenior['government_id'] = null; |
|
110 |
+ } else { |
|
111 |
+ newSenior['government_id'] = value; |
|
112 |
+ } |
|
113 |
+ newSenior['agency_id'] = null; |
|
114 |
+ setSenior(newSenior); |
|
115 |
+ } |
|
116 |
+ //등록할 시니어의 시행기관 변경 |
|
117 |
+ const seniorAgencyIdChange = (value) => { |
|
118 |
+ let newSenior = JSON.parse(JSON.stringify(senior)); |
|
119 |
+ if (CommonUtil.isEmpty(value) == true) { |
|
120 |
+ newSenior['agency_id'] = null; |
|
121 |
+ } else { |
|
122 |
+ newSenior['agency_id'] = value; |
|
123 |
+ } |
|
124 |
+ setSenior(newSenior); |
|
125 |
+ } |
|
126 |
+ //등록할 시니어의 기본 복약 정보 변경 |
|
127 |
+ const seniorMedicationChange = (value, isChecked) => { |
|
128 |
+ let newSenior = JSON.parse(JSON.stringify(senior)); |
|
129 |
+ let index = newSenior['seniorMedicationList'].indexOf(value); |
|
130 |
+ if (isChecked == true && index == -1) { |
|
131 |
+ newSenior['seniorMedicationList'].push(value); |
|
132 |
+ setSenior(newSenior); |
|
133 |
+ } else if (isChecked == false && index > -1) { |
|
134 |
+ newSenior['seniorMedicationList'].splice(index, 1); |
|
135 |
+ setSenior(newSenior); |
|
136 |
+ } else { |
|
137 |
+ return; |
|
138 |
+ } |
|
139 |
+ } |
|
140 |
+ |
|
141 |
+ |
|
142 |
+ //시니어 등록 유효성 검사 |
|
143 |
+ const seniorInsertValidation = () => { |
|
144 |
+ if (CommonUtil.isEmpty(senior['user_name']) == true) { |
|
145 |
+ seniorRef.current['user_name'].focus(); |
|
146 |
+ alert("이름을 입력해 주세요."); |
|
147 |
+ return false; |
|
148 |
+ } |
|
149 |
+ if (CommonUtil.isEmpty(senior['user_gender']) == true) { |
|
150 |
+ seniorRef.current['user_gender']['m'].focus(); |
|
151 |
+ alert("성별을 선택해 주세요."); |
|
152 |
+ return false; |
|
153 |
+ } |
|
154 |
+ if (CommonUtil.isEmpty(senior['user_birth']) == true) { |
|
155 |
+ seniorRef.current['user_birth'].focus(); |
|
156 |
+ alert("생년월일을 선택해 주세요."); |
|
157 |
+ return false; |
|
158 |
+ } |
|
159 |
+ if (CommonUtil.isEmpty(senior['user_phonenumber']) == true) { |
|
160 |
+ seniorRef.current['user_phonenumber'].focus(); |
|
161 |
+ alert("연락처를 입력해 주세요."); |
|
162 |
+ return false; |
|
163 |
+ } |
|
164 |
+ if (CommonUtil.isEmpty(senior['user_address']) == true) { |
|
165 |
+ seniorRef.current['user_address'].focus(); |
|
166 |
+ alert("주소를 입력해 주세요."); |
|
167 |
+ return false; |
|
168 |
+ } |
|
169 |
+ |
|
170 |
+ return true; |
|
171 |
+ } |
|
172 |
+ //시니어 등록 |
|
173 |
+ const seniorInsert = () => { |
|
174 |
+ if (seniorInsertValidation() == false) { |
|
175 |
+ return; |
|
176 |
+ } |
|
177 |
+ |
|
178 |
+ fetch("/user/seniorInsert.json", { |
|
179 |
+ method: "POST", |
|
180 |
+ headers: { |
|
181 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
182 |
+ }, |
|
183 |
+ body: JSON.stringify(senior), |
|
184 |
+ }).then((response) => response.json()).then((data) => { |
|
185 |
+ console.log("시니어 등록 결과(건수) : ", data); |
|
186 |
+ if (data > 0) { |
|
187 |
+ alert("등록완료"); |
|
188 |
+ seniorInsertCallback(); |
|
189 |
+ } else { |
|
190 |
+ alert("등록에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
191 |
+ } |
|
192 |
+ }).catch((error) => { |
|
193 |
+ console.log('seniorInsert() /user/seniorInsert.json error : ', error); |
|
194 |
+ }); |
|
195 |
+ } |
|
196 |
+ |
|
197 |
+ |
|
198 |
+ |
|
199 |
+ //Mounted |
|
200 |
+ React.useEffect(() => { |
|
201 |
+ orgSelectListOfHierarchy(); |
|
202 |
+ medicationTimeCodeSelectList(); |
|
203 |
+ }, []); |
|
204 |
+ |
|
205 |
+ //Mounted |
|
206 |
+ React.useEffect(() => { |
|
207 |
+ const government_id = !defaultGovernmentId ? state.loginUser['government_id'] : defaultGovernmentId; |
|
208 |
+ const agency_id = !defaultAgencyId ? state.loginUser['agency_id'] : defaultAgencyId; |
|
209 |
+ |
|
210 |
+ let newSenior = JSON.parse(JSON.stringify(senior)); |
|
211 |
+ newSenior['government_id'] = government_id; |
|
212 |
+ newSenior['agency_id'] = agency_id; |
|
213 |
+ setSenior(newSenior); |
|
214 |
+ }, [defaultGovernmentId, defaultAgencyId]); |
|
215 |
+ |
|
216 |
+ |
|
217 |
+ |
|
156 | 218 |
return ( |
157 | 219 |
<div class={open ? "openModal modal" : "modal"}> |
158 | 220 |
{open ? ( |
159 | 221 |
<div className="modal-inner"> |
160 | 222 |
<div className="modal-header flex"> |
161 |
- {header} |
|
162 |
- <Button className={"close"} onClick={noticeModalClose} btnName={"X"} /> |
|
223 |
+ 대상자(시니어) 등록 |
|
224 |
+ <button className={"close"} onClick={() => {close()}}>X</button> |
|
163 | 225 |
</div> |
164 | 226 |
<div className="modal-main"> |
165 |
- <div className="board-wrap"> |
|
166 |
- <SubTitle explanation={"회원 등록 시 ID는 연락처, 패스워드는 생년월일 8자리입니다."} className="margin-bottom" /> |
|
167 |
- <table className="margin-bottom2 senior-insert"> |
|
168 |
- {/* <tr> |
|
169 |
- <th>대상자등록번호</th> |
|
170 |
- <td colSpan={3} className="flex"> |
|
171 |
- <input type="text" placeholder="생성하기 버튼 클릭 시 자동으로 생성됩니다."/> |
|
172 |
- <Button |
|
173 |
- className={"btn-large gray-btn"} |
|
174 |
- btnName={"생성하기"} |
|
175 |
- /> |
|
176 |
- </td> |
|
177 |
- </tr> */} |
|
178 |
- {/* <tr> |
|
179 |
- <th>아이디</th> |
|
180 |
- <td> |
|
181 |
- <input type="text" value={`${telNum}_${userName}`.replace(/[-]/g,'')} onChange={handleUserId} onClick={(e) => settingBlor(e.target.value)} ref={inputRef} style={{backgroundColor : `#D3D3D3`}} readonly/> |
|
182 |
- </td> |
|
183 |
- </tr>*/} |
|
184 |
- <tr> |
|
185 |
- <th><span style={{color : "red"}}>*</span>이름</th> |
|
186 |
- <td> |
|
187 |
- <input type="text" value={userName} onChange={handleUserName} /> |
|
188 |
- </td> |
|
189 |
- <th><span style={{color : "red"}}>*</span>성별</th> |
|
190 |
- <td className=" gender"> |
|
191 |
- <div className="flex-start"> |
|
192 |
- <input type="radio" name="genderSelect" value="남" onChange={handleGender} /> |
|
193 |
- <label for="gender">남</label> |
|
194 |
- </div> |
|
195 |
- <div className="flex-start"> |
|
196 |
- <input type="radio" name="genderSelect" value="여" onChange={handleGender} /> |
|
197 |
- <label for="gender">여</label> |
|
198 |
- </div> |
|
199 |
- </td> |
|
200 |
- </tr> |
|
201 |
- <tr> |
|
202 |
- <th><span style={{color : "red"}}>*</span>생년월일</th> |
|
203 |
- <td> |
|
204 |
- <div className="flex"> |
|
205 |
- <input type='date' value={brith} onChange={handleBrithday} /> |
|
206 |
- </div> |
|
207 |
- </td> |
|
208 |
- {/* <th>요양등급</th> |
|
209 |
- <td> |
|
210 |
- <input type="text" /> |
|
211 |
- </td> */} |
|
227 |
+ <div className="board-wrap"> |
|
228 |
+ <SubTitle explanation={"회원 등록 시 ID는 연락처, 패스워드는 생년월일 8자리입니다."} className="margin-bottom" /> |
|
229 |
+ <table className="margin-bottom2 senior-insert"> |
|
230 |
+ <tr> |
|
231 |
+ <th>관리기관</th> |
|
232 |
+ <td> |
|
233 |
+ <select onChange={(e) => {seniorGovernmentIdChange(e.target.value)}}> |
|
234 |
+ <option value={''} selected={senior['government_id'] == null}>관리기관선택</option> |
|
235 |
+ {orgListOfHierarchy.map((item, idx) => { return ( |
|
236 |
+ <option key={idx} value={item['government_id']} selected={senior['government_id'] == item['government_id']}> |
|
237 |
+ {item['government_name']} |
|
238 |
+ </option> |
|
239 |
+ )})} |
|
240 |
+ </select> |
|
241 |
+ </td> |
|
242 |
+ <th>시행기관</th> |
|
243 |
+ <td> |
|
244 |
+ <select onChange={(e) => {seniorAgencyIdChange(e.target.value)}}> |
|
245 |
+ <option value={''} selected={senior['agency_id'] == null}>시행기관선택</option> |
|
246 |
+ {getAgencyList().map((item, idx) => { return ( |
|
247 |
+ <option key={idx} value={item['agency_id']} selected={senior['agency_id'] == item['agency_id']}> |
|
248 |
+ {item['agency_name']} |
|
249 |
+ </option> |
|
250 |
+ )})} |
|
251 |
+ </select> |
|
252 |
+ </td> |
|
253 |
+ </tr> |
|
254 |
+ <tr> |
|
255 |
+ <th><span style={{color : "red"}}>*</span>이름</th> |
|
256 |
+ <td> |
|
257 |
+ <input type="text" |
|
258 |
+ value={senior['user_name']} |
|
259 |
+ onChange={(e) => {seniorValueChange('user_name', e.target.value)}} |
|
260 |
+ ref={el => seniorRef.current['user_name'] = el} |
|
261 |
+ /> |
|
262 |
+ </td> |
|
263 |
+ <th><span style={{color : "red"}}>*</span>성별</th> |
|
264 |
+ <td className=" gender"> |
|
265 |
+ <div className="flex-start"> |
|
266 |
+ <input type="radio" id="user_gender_m" name="user_gender" value="남" |
|
267 |
+ onChange={(e) => {e.target.checked ? seniorValueChange('user_gender', e.target.value) : null}} |
|
268 |
+ ref={el => seniorRef.current['user_gender']['m'] = el} |
|
269 |
+ /> |
|
270 |
+ <label for="user_gender_m">남</label> |
|
271 |
+ </div> |
|
272 |
+ <div className="flex-start"> |
|
273 |
+ <input type="radio" id="user_gender_f" name="user_gender" value="여" |
|
274 |
+ onChange={(e) => {e.target.checked ? seniorValueChange('user_gender', e.target.value) : null}} |
|
275 |
+ ref={el => seniorRef.current['user_gender']['f'] = el} |
|
276 |
+ /> |
|
277 |
+ <label for="user_gender_f">여</label> |
|
278 |
+ </div> |
|
279 |
+ </td> |
|
280 |
+ </tr> |
|
281 |
+ <tr> |
|
282 |
+ <th><span style={{color : "red"}}>*</span>생년월일</th> |
|
283 |
+ <td> |
|
284 |
+ <div className="flex"> |
|
285 |
+ <input type='date' |
|
286 |
+ value={senior['user_birth']} |
|
287 |
+ onChange={(e) => {seniorValueChange('user_birth', e.target.value)}} |
|
288 |
+ ref={el => seniorRef.current['user_birth'] = el} |
|
289 |
+ /> |
|
290 |
+ </div> |
|
291 |
+ </td> |
|
292 |
+ </tr> |
|
293 |
+ <tr> |
|
294 |
+ <th><span style={{color : "red"}}>*</span>연락처</th> |
|
295 |
+ <td colSpan={3}> |
|
296 |
+ <input type="number" maxLength="11" |
|
297 |
+ value={senior['user_phonenumber']} |
|
298 |
+ onChange={(e) => {seniorValueChange('user_phonenumber', e.target.value)}} |
|
299 |
+ ref={el => seniorRef.current['user_phonenumber'] = el} |
|
300 |
+ /> |
|
301 |
+ </td> |
|
302 |
+ </tr> |
|
303 |
+ <tr> |
|
304 |
+ <th><span style={{color : "red"}}>*</span>주소</th> |
|
305 |
+ <td colSpan={3}> |
|
306 |
+ <input type="text" |
|
307 |
+ value={senior['user_address']} |
|
308 |
+ onChange={(e) => {seniorValueChange('user_address', e.target.value)}} |
|
309 |
+ ref={el => seniorRef.current['user_address'] = el} |
|
310 |
+ /> |
|
311 |
+ </td> |
|
312 |
+ </tr> |
|
313 |
+ <tr> |
|
314 |
+ <th>필요 복약</th> |
|
315 |
+ <td className="medicationTime-td"> |
|
316 |
+ <div className="flex"> |
|
317 |
+ {medicationTimeCodeList.map((item, idx) => { return ( |
|
318 |
+ <span key={idx}> |
|
319 |
+ <input type="checkbox" |
|
320 |
+ name="medicationTimeCodeList" |
|
321 |
+ id={item['medication_time_code']} |
|
322 |
+ value={item['medication_time_code']} |
|
323 |
+ onChange={(e) => {seniorMedicationChange(e.target.value, e.target.checked)}} |
|
324 |
+ checked={senior['seniorMedicationList'].indexOf(item['medication_time_code']) > -1}/> |
|
325 |
+ <label for={item['medication_time_code']}>{item['medication_time_code_name']}</label> |
|
326 |
+ </span> |
|
327 |
+ )})} |
|
328 |
+ </div> |
|
329 |
+ </td> |
|
330 |
+ </tr> |
|
331 |
+ <tr> |
|
332 |
+ <th>복용중인 약</th> |
|
333 |
+ <td colSpan={3}> |
|
334 |
+ <textarea className="medicine" cols="30" rows="2" value={senior['medication_pill']} onChange={(e) => {seniorValueChange('medication_pill', e.target.value)}} /> |
|
335 |
+ </td> |
|
336 |
+ </tr> |
|
337 |
+ <tr> |
|
338 |
+ <th>비고</th> |
|
339 |
+ <td colSpan={3}> |
|
340 |
+ <textarea className="note" cols="30" rows="2" value={senior['senior_note']} onChange={(e) => {seniorValueChange('senior_note', e.target.value)}} /> |
|
341 |
+ </td> |
|
342 |
+ </tr> |
|
212 | 343 |
|
213 |
- </tr> |
|
214 |
- <tr> |
|
215 |
- <th><span style={{color : "red"}}>*</span>연락처</th> |
|
216 |
- <td colSpan={3}> |
|
217 |
- <input type="text" maxLength="13" value={telNum} onChange={handleTelNum} /> |
|
218 |
- </td> |
|
219 |
- </tr> |
|
220 |
- <tr> |
|
221 |
- <th><span style={{color : "red"}}>*</span>주소</th> |
|
222 |
- <td colSpan={3}> |
|
223 |
- <input type="text" value={homeAddress} onChange={handleHomeAddress} /> |
|
224 |
- </td> |
|
225 |
- </tr> |
|
226 |
- <tr> |
|
227 |
- <th>필요 복약</th> |
|
228 |
- <td className="medicationTime-td"> |
|
229 |
- <div className="flex "> |
|
230 |
- <input type="checkbox" name="medicationSelect" checked={medicineM} onClick={(e) => { handleMedicineM(e) }} /><label for="medicationTime">아침</label> |
|
231 |
- <input type="checkbox" name="medicationSelect" checked={medicineL} onClick={(e) => { handleMedicineL(e) }} /><label for="medicationTime">점심</label> |
|
232 |
- <input type="checkbox" name="medicationSelect" checked={medicineD} onClick={(e) => { handleMedicineD(e) }} /><label for="medicationTime">저녁</label> |
|
233 |
- </div> |
|
234 |
- </td> |
|
235 |
- </tr> |
|
236 |
- <tr> |
|
237 |
- <th>복용중인 약</th> |
|
238 |
- <td colSpan={3}> |
|
239 |
- <textarea className="medicine" cols="30" rows="2" value={medication} onChange={handleMedication}></textarea> |
|
240 |
- </td> |
|
241 |
- </tr> |
|
242 |
- <tr> |
|
243 |
- <th>비고</th> |
|
244 |
- <td colSpan={3}> |
|
245 |
- <textarea className="note" cols="30" rows="2" value={note} onChange={handleNote}></textarea> |
|
246 |
- </td> |
|
247 |
- </tr> |
|
248 |
- |
|
249 |
- {/* <tr> |
|
250 |
- <th>기저질환</th> |
|
251 |
- <td colSpan={3}> |
|
252 |
- <textarea cols="30" rows="10"></textarea> |
|
253 |
- </td> |
|
254 |
- </tr> */} |
|
255 |
- </table> |
|
256 |
- <div className="btn-wrap flex-center"> |
|
257 |
- <Button |
|
258 |
- className={"btn-small gray-btn"} |
|
259 |
- btnName={"등록"} |
|
260 |
- onClick={() => { |
|
261 |
- InsertUserData(); |
|
262 |
- }} |
|
263 |
- /> |
|
264 |
- </div> |
|
265 |
- </div> |
|
344 |
+ {/* <tr> |
|
345 |
+ <th>기저질환</th> |
|
346 |
+ <td colSpan={3}> |
|
347 |
+ <textarea cols="30" rows="10"></textarea> |
|
348 |
+ </td> |
|
349 |
+ </tr> */} |
|
350 |
+ </table> |
|
351 |
+ <div className="btn-wrap flex-center"> |
|
352 |
+ <button className={"btn-small gray-btn"} onClick={seniorInsert}>등록</button> |
|
353 |
+ </div> |
|
354 |
+ </div> |
|
266 | 355 |
</div> |
267 | 356 |
</div> |
268 | 357 |
) : null} |
+++ client/views/component/Modal_SeniorInsert_back_230329.jsx
... | ... | @@ -0,0 +1,271 @@ |
1 | +import React from "react"; | |
2 | +import Button from "./Button.jsx"; | |
3 | +import SubTitle from "./SubTitle.jsx"; | |
4 | + | |
5 | +export default function Modal({ open, close, header, setModalOpen3, setAddSenior }) { | |
6 | + // 사용자 등록 시 초기값 세팅 | |
7 | + // const [seniorId, setSeniorId] = React.useState(""); | |
8 | + const [userName, setUserName] = React.useState(""); | |
9 | + const [gender, setGender] = React.useState(""); | |
10 | + const [brith, setBrith] = React.useState(""); | |
11 | + const [telNum, setTelNum] = React.useState(""); | |
12 | + const [homeAddress, setHomeAddress] = React.useState(""); | |
13 | + const [medicineM, setMedicineM] = React.useState(false); | |
14 | + const [medicineL, setMedicineL] = React.useState(false); | |
15 | + const [medicineD, setMedicineD] = React.useState(false); | |
16 | + const [medication, setMedication] = React.useState(""); | |
17 | + const [note, setNote] = React.useState(""); | |
18 | + | |
19 | + // //id blor 처리 진행 | |
20 | + // const inputRef = React.useRef(); | |
21 | + // const settingBlor = (e) => { | |
22 | + // inputRef.current.blur(); | |
23 | + // } | |
24 | + | |
25 | + // 등록 후 초기화 진행 | |
26 | + const dataReset = () => { | |
27 | + // setSeniorId(""); | |
28 | + setUserName(""); | |
29 | + setGender(""); | |
30 | + setBrith(""); | |
31 | + setTelNum(""); | |
32 | + setHomeAddress(""); | |
33 | + setMedicineM(""); | |
34 | + setMedicineL(""); | |
35 | + setMedicineD(""); | |
36 | + setMedication(""); | |
37 | + setNote(""); | |
38 | + } | |
39 | + //-------- 변경되는 데이터 Handler 설정 --------// | |
40 | + // const handleUserId = (e) => { | |
41 | + // console.log(e.target.value); | |
42 | + // setSeniorId(e.target.value); | |
43 | + // }; | |
44 | + const handleUserName = (e) => { | |
45 | + e.target.value=e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, ''); | |
46 | + setUserName(e.target.value); | |
47 | + }; | |
48 | + const handleGender = (e) => { | |
49 | + setGender(e.target.value); | |
50 | + }; | |
51 | + const handleBrithday = (e) => { | |
52 | + setBrith(e.target.value); | |
53 | + }; | |
54 | + const handleTelNum = (e) => { | |
55 | + e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`); | |
56 | + setTelNum(e.target.value); | |
57 | + }; | |
58 | + const handleHomeAddress = (e) => { | |
59 | + setHomeAddress(e.target.value); | |
60 | + }; | |
61 | + const handleMedicineM = (e) => { | |
62 | + setMedicineM(e.target.checked); | |
63 | + }; | |
64 | + const handleMedicineL = (e) => { | |
65 | + setMedicineL(e.target.checked); | |
66 | + }; | |
67 | + const handleMedicineD = (e) => { | |
68 | + setMedicineD(e.target.checked); | |
69 | + }; | |
70 | + const handleMedication = (e) => { | |
71 | + setMedication(e.target.value); | |
72 | + }; | |
73 | + const handleNote = (e) => { | |
74 | + setNote(e.target.value); | |
75 | + }; | |
76 | + | |
77 | + //-------- 등록 버튼 동작 수행 영역 시작 --------// | |
78 | + // 대상자 정보 등록을 위한 함수 | |
79 | + const InsertUserData = () => { | |
80 | + //-------- 유효성 체크 --------// | |
81 | + if(userName == ""){ | |
82 | + alert("이름을 입력해 주세요."); | |
83 | + return ; | |
84 | + } else if(gender == "") { | |
85 | + alert("성별을 선택해 주세요."); | |
86 | + return ; | |
87 | + } else if(brith == "") { | |
88 | + alert("생년월일을 선택해 주세요."); | |
89 | + return ; | |
90 | + } else if(telNum == "") { | |
91 | + alert("연락처를 입력해 선택해 주세요."); | |
92 | + return ; | |
93 | + } else if(homeAddress == "") { | |
94 | + alert("주소를 선택해 주세요."); | |
95 | + return ; | |
96 | + } | |
97 | + var insertBtn = confirm("등록하시겠습니까?"); | |
98 | + if (insertBtn) { | |
99 | + fetch("/user/insertUserData.json", { | |
100 | + method: "POST", | |
101 | + headers: { | |
102 | + 'Content-Type': 'application/json; charset=UTF-8' | |
103 | + }, | |
104 | + body: JSON.stringify({ | |
105 | + user_name: userName, | |
106 | + user_gender: gender, | |
107 | + user_birth: brith, | |
108 | + user_phonenumber: telNum, | |
109 | + user_address: homeAddress, | |
110 | + agency_id: 'AGENCY01', | |
111 | + government_id: 'GOVERNMENT01', | |
112 | + authority: 'SENIOR01', | |
113 | + }), | |
114 | + }).then((response) => response.json()).then((data) => { | |
115 | + console.log("대상자 정보 등록"); | |
116 | + InsertUserPillData(); | |
117 | + }).catch((error) => { | |
118 | + console.log('insertUserData() /user/insertUserData.json error : ', error); | |
119 | + }); | |
120 | + } else { | |
121 | + return; | |
122 | + } | |
123 | + }; | |
124 | + // 대상자 약 복용 정보 등록을 위한 함수 | |
125 | + const InsertUserPillData = () => { | |
126 | + fetch("/user/insertSeniorMadication.json", { | |
127 | + method: "POST", | |
128 | + headers: { | |
129 | + 'Content-Type': 'application/json; charset=UTF-8' | |
130 | + }, | |
131 | + body: JSON.stringify({ | |
132 | + user_phonenumber: telNum, | |
133 | + breakfast_medication_check: medicineM, | |
134 | + lunch_medication_check: medicineL, | |
135 | + dinner_medication_check: medicineD, | |
136 | + medication_pill: medication, | |
137 | + senior_note: note, | |
138 | + }), | |
139 | + }).then((response) => response.json()).then((data) => { | |
140 | + console.log("약 정보 등록"); | |
141 | + dataReset(); | |
142 | + setAddSenior(true) | |
143 | + alert("등록 되었습니다."); | |
144 | + noticeModalClose() | |
145 | + | |
146 | + }).catch((error) => { | |
147 | + console.log('InsertUserPillData() /user/insertSeniorMadication.json error : ', error); | |
148 | + }); | |
149 | + }; | |
150 | + //-------- 등록 버튼 동작 수행 영역 끝 --------/ | |
151 | + //-------- 모달 종료 --------> | |
152 | + const noticeModalClose = () => { | |
153 | + dataReset(); | |
154 | + setModalOpen3(false); | |
155 | + }; | |
156 | + return ( | |
157 | + <div class={open ? "openModal modal" : "modal"}> | |
158 | + {open ? ( | |
159 | + <div className="modal-inner"> | |
160 | + <div className="modal-header flex"> | |
161 | + {header} | |
162 | + <Button className={"close"} onClick={noticeModalClose} btnName={"X"} /> | |
163 | + </div> | |
164 | + <div className="modal-main"> | |
165 | + <div className="board-wrap"> | |
166 | + <SubTitle explanation={"회원 등록 시 ID는 연락처, 패스워드는 생년월일 8자리입니다."} className="margin-bottom" /> | |
167 | + <table className="margin-bottom2 senior-insert"> | |
168 | + {/* <tr> | |
169 | + <th>대상자등록번호</th> | |
170 | + <td colSpan={3} className="flex"> | |
171 | + <input type="text" placeholder="생성하기 버튼 클릭 시 자동으로 생성됩니다."/> | |
172 | + <Button | |
173 | + className={"btn-large gray-btn"} | |
174 | + btnName={"생성하기"} | |
175 | + /> | |
176 | + </td> | |
177 | + </tr> */} | |
178 | + {/* <tr> | |
179 | + <th>아이디</th> | |
180 | + <td> | |
181 | + <input type="text" value={`${telNum}_${userName}`.replace(/[-]/g,'')} onChange={handleUserId} onClick={(e) => settingBlor(e.target.value)} ref={inputRef} style={{backgroundColor : `#D3D3D3`}} readonly/> | |
182 | + </td> | |
183 | + </tr>*/} | |
184 | + <tr> | |
185 | + <th><span style={{color : "red"}}>*</span>이름</th> | |
186 | + <td> | |
187 | + <input type="text" value={userName} onChange={handleUserName} /> | |
188 | + </td> | |
189 | + <th><span style={{color : "red"}}>*</span>성별</th> | |
190 | + <td className=" gender"> | |
191 | + <div className="flex-start"> | |
192 | + <input type="radio" name="genderSelect" value="남" onChange={handleGender} /> | |
193 | + <label for="gender">남</label> | |
194 | + </div> | |
195 | + <div className="flex-start"> | |
196 | + <input type="radio" name="genderSelect" value="여" onChange={handleGender} /> | |
197 | + <label for="gender">여</label> | |
198 | + </div> | |
199 | + </td> | |
200 | + </tr> | |
201 | + <tr> | |
202 | + <th><span style={{color : "red"}}>*</span>생년월일</th> | |
203 | + <td> | |
204 | + <div className="flex"> | |
205 | + <input type='date' value={brith} onChange={handleBrithday} /> | |
206 | + </div> | |
207 | + </td> | |
208 | + {/* <th>요양등급</th> | |
209 | + <td> | |
210 | + <input type="text" /> | |
211 | + </td> */} | |
212 | + | |
213 | + </tr> | |
214 | + <tr> | |
215 | + <th><span style={{color : "red"}}>*</span>연락처</th> | |
216 | + <td colSpan={3}> | |
217 | + <input type="text" maxLength="13" value={telNum} onChange={handleTelNum} /> | |
218 | + </td> | |
219 | + </tr> | |
220 | + <tr> | |
221 | + <th><span style={{color : "red"}}>*</span>주소</th> | |
222 | + <td colSpan={3}> | |
223 | + <input type="text" value={homeAddress} onChange={handleHomeAddress} /> | |
224 | + </td> | |
225 | + </tr> | |
226 | + <tr> | |
227 | + <th>필요 복약</th> | |
228 | + <td className="medicationTime-td"> | |
229 | + <div className="flex "> | |
230 | + <input type="checkbox" name="medicationSelect" checked={medicineM} onClick={(e) => { handleMedicineM(e) }} /><label for="medicationTime">아침</label> | |
231 | + <input type="checkbox" name="medicationSelect" checked={medicineL} onClick={(e) => { handleMedicineL(e) }} /><label for="medicationTime">점심</label> | |
232 | + <input type="checkbox" name="medicationSelect" checked={medicineD} onClick={(e) => { handleMedicineD(e) }} /><label for="medicationTime">저녁</label> | |
233 | + </div> | |
234 | + </td> | |
235 | + </tr> | |
236 | + <tr> | |
237 | + <th>복용중인 약</th> | |
238 | + <td colSpan={3}> | |
239 | + <textarea className="medicine" cols="30" rows="2" value={medication} onChange={handleMedication}></textarea> | |
240 | + </td> | |
241 | + </tr> | |
242 | + <tr> | |
243 | + <th>비고</th> | |
244 | + <td colSpan={3}> | |
245 | + <textarea className="note" cols="30" rows="2" value={note} onChange={handleNote}></textarea> | |
246 | + </td> | |
247 | + </tr> | |
248 | + | |
249 | + {/* <tr> | |
250 | + <th>기저질환</th> | |
251 | + <td colSpan={3}> | |
252 | + <textarea cols="30" rows="10"></textarea> | |
253 | + </td> | |
254 | + </tr> */} | |
255 | + </table> | |
256 | + <div className="btn-wrap flex-center"> | |
257 | + <Button | |
258 | + className={"btn-small gray-btn"} | |
259 | + btnName={"등록"} | |
260 | + onClick={() => { | |
261 | + InsertUserData(); | |
262 | + }} | |
263 | + /> | |
264 | + </div> | |
265 | + </div> | |
266 | + </div> | |
267 | + </div> | |
268 | + ) : null} | |
269 | + </div> | |
270 | + ); | |
271 | +} |
--- client/views/component/Pagination.jsx
+++ client/views/component/Pagination.jsx
... | ... | @@ -1,17 +1,57 @@ |
1 | 1 |
import React from "react"; |
2 | 2 |
import styled from "styled-components"; |
3 | 3 |
|
4 |
-export default function Pagination({ total, limit, page, setPage }) { |
|
5 |
- const numPages = Math.ceil(total / limit); |
|
4 |
+export default function Pagination({ currentPage, perPage, totalCount, maxRange, click }) { |
|
5 |
+ |
|
6 |
+ const startPage = () => { |
|
7 |
+ return Math.floor((currentPage - 1) / maxRange) * maxRange + 1; |
|
8 |
+ } |
|
9 |
+ const endPage = () => { |
|
10 |
+ if (maxEndPage() < currentEndPage()) { |
|
11 |
+ return maxEndPage(); |
|
12 |
+ } else { |
|
13 |
+ return currentEndPage(); |
|
14 |
+ } |
|
15 |
+ } |
|
16 |
+ const currentEndPage = () => { |
|
17 |
+ return maxRange * Math.ceil((currentPage / maxRange)); |
|
18 |
+ } |
|
19 |
+ const maxEndPage = () => { |
|
20 |
+ return Math.ceil(totalCount / perPage); |
|
21 |
+ } |
|
22 |
+ const createRange = () => { |
|
23 |
+ var range = []; |
|
24 |
+ for (var i = startPage(); i <= endPage(); i++) { |
|
25 |
+ range.push(i); |
|
26 |
+ } |
|
27 |
+ return range; |
|
28 |
+ } |
|
29 |
+ |
|
30 |
+ const excute = (i) => { |
|
31 |
+ if (i >= 1 && i <= maxEndPage()) { |
|
32 |
+ if (i != currentPage) { |
|
33 |
+ click(i);//부모 function 실행 |
|
34 |
+ } else { |
|
35 |
+ return; |
|
36 |
+ } |
|
37 |
+ } else { |
|
38 |
+ alert('이동할 페이지가 없습니다.'); |
|
39 |
+ } |
|
40 |
+ } |
|
6 | 41 |
|
7 | 42 |
return ( |
8 | 43 |
<> |
9 | 44 |
<Paging> |
10 |
- <button onClick={() => setPage(page - 1)} disabled={page === 1}><</button> |
|
11 |
- {Array(numPages).fill().map((_, i) => ( |
|
12 |
- <button key={i + 1} onClick={() => setPage(i + 1)} aria-current={page === i + 1 ? "page" : null} className={page === i + 1 ? "PagingBtn" : null}> {i + 1} </button> |
|
45 |
+ <button onClick={() => excute(currentPage - 1)} disabled={currentPage === 1}><</button> |
|
46 |
+ {createRange().map((page, i) => ( |
|
47 |
+ <button |
|
48 |
+ key={page} onClick={() => excute(page)} |
|
49 |
+ className={currentPage === page ? "PagingBtn" : null} |
|
50 |
+ aria-current={currentPage === page ? "page" : null}> |
|
51 |
+ {page} |
|
52 |
+ </button> |
|
13 | 53 |
))} |
14 |
- <button onClick={() => setPage(page + 1)} disabled={page === numPages}>></button> |
|
54 |
+ <button onClick={() => excute(currentPage + 1)} disabled={currentPage === maxEndPage()}>></button> |
|
15 | 55 |
</Paging> |
16 | 56 |
</> |
17 | 57 |
); |
--- client/views/index.html
+++ client/views/index.html
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 |
<meta name="description" content="Node React Web"> |
8 | 8 |
<link rel="icon" href="" /> |
9 | 9 |
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey= 557664ec353e27affe3d6c3c513b7183"></script> |
10 |
- <title>올잇메디</title> |
|
10 |
+ <title>시니어 케어 시스템</title> |
|
11 | 11 |
</head> |
12 | 12 |
|
13 | 13 |
<body> |
--- client/views/index.jsx
+++ client/views/index.jsx
... | ... | @@ -7,6 +7,10 @@ |
7 | 7 |
import React from "react"; |
8 | 8 |
import ReactDOM from "react-dom/client"; |
9 | 9 |
import { BrowserRouter } from "react-router-dom"; |
10 |
+import { Provider } from "react-redux"; |
|
11 |
+ |
|
12 |
+//Application의 전역 상태값(변수) 저장소(Store) 관리 Component |
|
13 |
+import AppStore from "./pages/AppStore.jsx"; |
|
10 | 14 |
|
11 | 15 |
//Application Root component |
12 | 16 |
import App from "./pages/App.jsx"; |
... | ... | @@ -20,6 +24,8 @@ |
20 | 24 |
const root = ReactDOM.createRoot(document.getElementById("root")); |
21 | 25 |
root.render( |
22 | 26 |
<BrowserRouter> |
23 |
- <App /> |
|
27 |
+ <Provider store={AppStore}> |
|
28 |
+ <App /> |
|
29 |
+ </Provider> |
|
24 | 30 |
</BrowserRouter> |
25 | 31 |
); |
--- client/views/layout/Header.jsx
+++ client/views/layout/Header.jsx
... | ... | @@ -1,13 +1,32 @@ |
1 | 1 |
import React from "react"; |
2 |
+import { useSelector } from "react-redux"; |
|
3 |
+ |
|
2 | 4 |
import MenuIcon from "@mui/icons-material/Menu"; |
3 | 5 |
import Weather from "../pages/main/Weather.jsx"; |
4 | 6 |
import PersonIcon from "@mui/icons-material/Person"; |
5 | 7 |
import { useNavigate } from "react-router"; |
6 | 8 |
import logo from "../../resources/files/images/logo.png"; |
7 | 9 |
|
8 |
-function Header({ title }) { |
|
10 |
+function Header() { |
|
9 | 11 |
const navigate = useNavigate(); |
10 |
- const [headerData, setHeaderData] = React.useState(0); |
|
12 |
+ |
|
13 |
+ //전역 변수 저장 객체 |
|
14 |
+ const state = useSelector((state) => {return state}); |
|
15 |
+ |
|
16 |
+ //App Title |
|
17 |
+ const [title, setTitle] = React.useState(''); |
|
18 |
+ |
|
19 |
+ React.useEffect(() => { |
|
20 |
+ if (state.loginUser['authority'] == 'ROLE_ADMIN') { |
|
21 |
+ setTitle('올잇메디'); |
|
22 |
+ } else if (state.loginUser['authority'] == 'ROLE_GOVERNMENT') { |
|
23 |
+ setTitle(state.loginUser['government_name']); |
|
24 |
+ } else if (state.loginUser['authority'] == 'ROLE_AGENCY') { |
|
25 |
+ setTitle(state.loginUser['agency_name']); |
|
26 |
+ } else if (state.loginUser['authority'] == 'ROLE_GUARDIAN') { |
|
27 |
+ setTitle('보호자'); |
|
28 |
+ } |
|
29 |
+ }, [state.loginUser['authority']]); |
|
11 | 30 |
|
12 | 31 |
return ( |
13 | 32 |
<header> |
... | ... | @@ -17,8 +36,8 @@ |
17 | 36 |
<div className="page-title flex flex-align"> |
18 | 37 |
{/* <MenuIcon /> */} |
19 | 38 |
<div className="info-wrap flex"> |
20 |
- <div className="usericon"><PersonIcon sx={{ width:48, height:48,}} /></div> |
|
21 |
- <p className="header-info-id">admin1</p> |
|
39 |
+ {/* <div className="usericon"><PersonIcon sx={{ width:48, height:48,}} /></div> */} |
|
40 |
+ <p className="header-info-id">{state.loginUser['user_name']}({state.loginUser['user_id']})</p> |
|
22 | 41 |
</div> |
23 | 42 |
<Weather /> |
24 | 43 |
</div> |
--- client/views/layout/Menu.jsx
+++ client/views/layout/Menu.jsx
... | ... | @@ -12,6 +12,26 @@ |
12 | 12 |
} |
13 | 13 |
const navigate = useNavigate(); |
14 | 14 |
|
15 |
+ //로그아웃 |
|
16 |
+ const logout = () => { |
|
17 |
+ fetch("/user/logout.json", { |
|
18 |
+ method: "POST", |
|
19 |
+ headers: { |
|
20 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
21 |
+ }, |
|
22 |
+ /* body: JSON.stringify({}), */ |
|
23 |
+ }).then((response) => response.json()).then((data) => { |
|
24 |
+ console.log("로그아웃 결과 : ", data); |
|
25 |
+ if (data == true) { |
|
26 |
+ navigate('/Main'); |
|
27 |
+ } else { |
|
28 |
+ alert('로그아웃 실패, 관리자에게 문의바랍니다.'); |
|
29 |
+ } |
|
30 |
+ }).catch((error) => { |
|
31 |
+ console.log('logout() /user/logout.json error : ', error); |
|
32 |
+ }); |
|
33 |
+ }; |
|
34 |
+ |
|
15 | 35 |
return ( |
16 | 36 |
<> |
17 | 37 |
<nav |
... | ... | @@ -30,7 +50,7 @@ |
30 | 50 |
<div className="info-id" ><span onClick={() => { |
31 | 51 |
navigate("/Join"); |
32 | 52 |
}}>계정추가</span></div> |
33 |
- <div className="logout"><span>로그아웃</span></div> |
|
53 |
+ <div className="logout" onClick={logout}><span>로그아웃</span></div> |
|
34 | 54 |
</div> |
35 | 55 |
</nav> |
36 | 56 |
|
--- client/views/pages/App.jsx
+++ client/views/pages/App.jsx
... | ... | @@ -4,6 +4,11 @@ |
4 | 4 |
* @dscription : React를 활용한 Client단 구현 대상인 Application의 시작점(Index) Component 입니다. |
5 | 5 |
*/ |
6 | 6 |
import React from "react"; |
7 |
+import { useSelector, useDispatch } from "react-redux"; |
|
8 |
+import { useLocation, /* useNavigate */ } from "react-router"; |
|
9 |
+ |
|
10 |
+//Application의 전역 상태값(변수) 저장소(Store) 관리 Component |
|
11 |
+import { setLoginUser } from "./AppStore.jsx"; |
|
7 | 12 |
|
8 | 13 |
//Application의 Route 정보를 관리하는 Component |
9 | 14 |
import AllApp, {AdminApp, GovernmentApp, AgencyApp, GuardianApp} from "./AppRoute.jsx"; |
... | ... | @@ -12,44 +17,87 @@ |
12 | 17 |
import Header from "../layout/Header.jsx"; |
13 | 18 |
import Menu from "../layout/Menu.jsx"; |
14 | 19 |
import Login from "./login/Login.jsx"; |
15 |
-import { useLocation, useNavigate } from "react-router"; |
|
16 | 20 |
import Weather from "./main/Weather.jsx"; |
17 | 21 |
|
18 | 22 |
function App() { |
19 | 23 |
const location = useLocation(); |
20 |
- const navigate = useNavigate(); |
|
21 |
- const [isLogin, setIsLogin] = React.useState(true); |
|
24 |
+ //const navigate = useNavigate(); |
|
22 | 25 |
|
23 |
- const getLogin = () => { |
|
24 |
- setIsLogin(true); |
|
25 |
- navigate("/Main"); |
|
26 |
+ //전역 변수 저장 객체 |
|
27 |
+ const state = useSelector((state) => {return state}); |
|
28 |
+ const dispatch = useDispatch(); |
|
29 |
+ |
|
30 |
+ //로그인 여부 |
|
31 |
+ const [isLogin, setIsLogin] = React.useState(false); |
|
32 |
+ |
|
33 |
+ //로그인에 따라 각기 다른 App 주입 대상 변수(AdminApp, GovernmentApp, AgencyApp, GuardianApp) |
|
34 |
+ const [appRoute, setAppRoute] = React.useState(null); |
|
35 |
+ const [menuItems, setMenuItems] = React.useState(null); |
|
36 |
+ |
|
37 |
+ //로그인 사용자 조회 |
|
38 |
+ const loginUserSelectOne = (clientLoginCheck) => { |
|
39 |
+ fetch("/user/loginUserSelectOne.json", { |
|
40 |
+ method: "POST", |
|
41 |
+ headers: { |
|
42 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
43 |
+ }, |
|
44 |
+ body: JSON.stringify({}), |
|
45 |
+ }).then((response) => response.json()).then((data) => { |
|
46 |
+ console.log("로그인 결과 : ", data); |
|
47 |
+ //로그인 사용자 정보 전역 변수에 저장 |
|
48 |
+ dispatch(setLoginUser(data)); |
|
49 |
+ //클라이언트 로그인 체크 (콜백) |
|
50 |
+ clientLoginCheck(data); |
|
51 |
+ }).catch((error) => { |
|
52 |
+ console.log('login() /user/loginUserSelectOne.json error : ', error); |
|
53 |
+ }); |
|
26 | 54 |
}; |
27 | 55 |
|
56 |
+ //URL 변경 시, 발생 이벤트(hook) |
|
57 |
+ React.useEffect(() => { |
|
58 |
+ console.log('location : ', location); |
|
59 |
+ loginUserSelectOne((loginResultData) => { |
|
60 |
+ //console.log('loginResultData : ', loginResultData); |
|
61 |
+ //console.log('isLogin : ', isLogin, ', authority : ', loginResultData['authority']); |
|
28 | 62 |
|
29 |
- const menuItems = AgencyApp.menuItems; //AdminApp, GovernmentApp, AllApp, AgencyApp, GuardianApp |
|
30 |
- const AppRoute = AgencyApp.AppRoute; |
|
63 |
+ //로그인 유무(로그인 정보가 있으면 True, 없으면 False) |
|
64 |
+ let isLogin = (loginResultData != null && loginResultData['user_id'] != null); |
|
65 |
+ setIsLogin(isLogin); |
|
31 | 66 |
|
67 |
+ //로그인 -> 권한에 따른 App 주입 |
|
68 |
+ if (isLogin == true) { |
|
69 |
+ if (loginResultData['authority'] == 'ROLE_ADMIN') { |
|
70 |
+ setMenuItems(AdminApp.menuItems); |
|
71 |
+ setAppRoute(<AdminApp.AppRoute/>); |
|
72 |
+ } else if (loginResultData['authority'] == 'ROLE_GOVERNMENT') { |
|
73 |
+ setMenuItems(GovernmentApp.menuItems); |
|
74 |
+ setAppRoute(<GovernmentApp.AppRoute/>); |
|
75 |
+ } else if (loginResultData['authority'] == 'ROLE_AGENCY') { |
|
76 |
+ setMenuItems(AgencyApp.menuItems); |
|
77 |
+ setAppRoute(<AgencyApp.AppRoute/>); |
|
78 |
+ } else if (loginResultData['authority'] == 'ROLE_GUARDIAN') { |
|
79 |
+ setMenuItems(GuardianApp.menuItems); |
|
80 |
+ setAppRoute(<GuardianApp.AppRoute/>); |
|
81 |
+ } else { |
|
82 |
+ alert('권한 관련 에러 - 관리자에게 문의바랍니다.'); |
|
83 |
+ console.log('권한 관련 에러 - 관리자에게 문의바랍니다 : ', loginResultData); |
|
84 |
+ } |
|
85 |
+ } |
|
86 |
+ }); |
|
87 |
+ }, [location]); |
|
32 | 88 |
|
33 |
- const { title } = menuItems.find( |
|
34 |
- (item) => |
|
35 |
- item.path === location.pathname || |
|
36 |
- location.pathname.startsWith(item.prefix) || |
|
37 |
- item.childrens?.some((child) => location.pathname.startsWith(child.path)) |
|
38 |
- ) ?? { title: '' }; |
|
39 | 89 |
|
40 | 90 |
return ( |
41 | 91 |
<div id="App"> |
42 |
- {isLogin ? ( |
|
92 |
+ {isLogin == true ? ( |
|
43 | 93 |
<div id="layout"> |
44 |
- <Header title={title} /> |
|
45 |
- <Menu items={menuItems}/> |
|
94 |
+ <Header/> |
|
95 |
+ <Menu items={menuItems != null ? menuItems : null}/> |
|
46 | 96 |
<div id="pages"> |
47 |
- <AppRoute /> |
|
97 |
+ {appRoute != null ? appRoute : null} |
|
48 | 98 |
</div> |
49 | 99 |
</div> |
50 |
- ) : ( |
|
51 |
- <Login getLogin={getLogin} /> |
|
52 |
- )} |
|
100 |
+ ) : (<Login/>)} |
|
53 | 101 |
</div> |
54 | 102 |
); |
55 | 103 |
} |
--- client/views/pages/AppRoute.jsx
+++ client/views/pages/AppRoute.jsx
... | ... | @@ -17,7 +17,6 @@ |
17 | 17 |
import ApartmentIcon from '@mui/icons-material/Apartment'; |
18 | 18 |
import LocalHospitalIcon from '@mui/icons-material/LocalHospital'; |
19 | 19 |
|
20 |
-import Test from "./test/Test.jsx"; |
|
21 | 20 |
import Main_government from "./main/Main_government.jsx"; |
22 | 21 |
import Main_guardian from "./main/Main_guardian.jsx"; |
23 | 22 |
import Main_agency from "./main/Main_agency.jsx"; |
... | ... | @@ -255,6 +254,7 @@ |
255 | 254 |
function AllAppRoute() { |
256 | 255 |
return ( |
257 | 256 |
<Routes> |
257 |
+ |
|
258 | 258 |
<Route path="/Medicalcare" element={<Medicalcare />}></Route> |
259 | 259 |
<Route path="/Healthcare" element={<Healthcare />}></Route> |
260 | 260 |
<Route path="/QuestionConfirm/:qnaIdx" element={<QuestionConfirm />}></Route> |
... | ... | @@ -332,7 +332,6 @@ |
332 | 332 |
<Route path="/SeniorEdit/:seniorId" element={<SeniorEdit />}></Route> |
333 | 333 |
<Route path="/AgencyInsert" element={<AgencyInsert />}></Route> |
334 | 334 |
<Route path="/Join" element={<Join />}></Route> |
335 |
- <Route path="/Test" element={<Test />}></Route> |
|
336 | 335 |
<Route path="/Main" element={<Main />}></Route> |
337 | 336 |
<Route |
338 | 337 |
path="/EquipmentRentalInsert" |
... | ... | @@ -423,9 +422,9 @@ |
423 | 422 |
function AdminAppRoute() { |
424 | 423 |
return ( |
425 | 424 |
<Routes> |
425 |
+ |
|
426 | 426 |
<Route path="/Medicalcare" element={<Medicalcare />}></Route> |
427 | 427 |
<Route path="/Healthcare" element={<Healthcare />}></Route> |
428 |
- <Route path="/Test" element={<Test />}></Route> |
|
429 | 428 |
<Route path="/Main" element={<Main />}></Route> |
430 | 429 |
<Route |
431 | 430 |
path="/EquipmentRentalInsert" |
... | ... | @@ -460,6 +459,9 @@ |
460 | 459 |
<Route path="/EquipmentManagementSelectAdd" element={<EquipmentManagementSelectAdd />}></Route> |
461 | 460 |
<Route path="/UserAuthoriySelect" element={<UserAuthoriySelect />}></Route> |
462 | 461 |
<Route path="/QandAConfirm" element={<QandAConfirm />}></Route> |
462 |
+ <Route path="/Join" element={<Join />}></Route> |
|
463 |
+ <Route path="/SeniorEdit" element={<SeniorEdit />}></Route> |
|
464 |
+ <Route path="/SeniorSelectOne" element={<SeniorSelectOne />}></Route> |
|
463 | 465 |
</Routes> |
464 | 466 |
); |
465 | 467 |
} |
... | ... | @@ -468,7 +470,7 @@ |
468 | 470 |
const GovernmentAppMenuItems = [ |
469 | 471 |
{ |
470 | 472 |
title: "Home", |
471 |
- path: "/Main_government", |
|
473 |
+ path: "/Main", |
|
472 | 474 |
icon: <HouseIcon sx={{ fontSize: 20, color: "#333333", marginRight: 1 }} />, |
473 | 475 |
}, |
474 | 476 |
{ |
... | ... | @@ -520,19 +522,20 @@ |
520 | 522 |
title: "위험 기준 관리", |
521 | 523 |
path: "/RiskSet", |
522 | 524 |
}, |
523 |
- { |
|
525 |
+ /* { |
|
524 | 526 |
title: "사용자 권한 관리", |
525 | 527 |
path: "/AuthorityManagement", |
526 |
- }, |
|
528 |
+ }, */ |
|
527 | 529 |
], |
528 | 530 |
}, |
529 | 531 |
]; |
530 | 532 |
function GovernmentAppRoute() { |
531 | 533 |
return ( |
532 | 534 |
<Routes> |
535 |
+ |
|
533 | 536 |
<Route path="/Medicalcare" element={<Medicalcare />}></Route> |
534 | 537 |
<Route path="/Healthcare" element={<Healthcare />}></Route> |
535 |
- <Route path="/Main_government" element={<Main_government />}></Route> |
|
538 |
+ <Route path="/Main" element={<Main_government />}></Route> |
|
536 | 539 |
<Route path="/AgencySelect" element={<AgencySelect />}></Route> |
537 | 540 |
<Route path="/UserSelectOk" element={<UserSelectOk />}></Route> |
538 | 541 |
<Route |
... | ... | @@ -554,7 +557,7 @@ |
554 | 557 |
element={<UserAuthoriySelect />} |
555 | 558 |
></Route> |
556 | 559 |
<Route path="/RiskSet" element={<RiskSet />}></Route> |
557 |
- <Route path="/AuthorityManagement" element={<AuthorityManagement />}></Route> |
|
560 |
+ {/* <Route path="/AuthorityManagement" element={<AuthorityManagement />}></Route> */} |
|
558 | 561 |
<Route path="/QandASelect" element={<QandASelect />}></Route> |
559 | 562 |
<Route path="/QandAConfirm" element={<QandAConfirm />}></Route> |
560 | 563 |
<Route path="/QandAInsert" element={<QandAInsert />}></Route> |
... | ... | @@ -568,7 +571,7 @@ |
568 | 571 |
const AgencyAppMenuItems = [ |
569 | 572 |
{ |
570 | 573 |
title: "Home", |
571 |
- path: "/Main_agency", |
|
574 |
+ path: "/Main", |
|
572 | 575 |
icon: <HouseIcon sx={{ fontSize: 20, color: "#333333", marginRight: 1 }} />, |
573 | 576 |
}, |
574 | 577 |
{ |
... | ... | @@ -621,12 +624,13 @@ |
621 | 624 |
function AgencyAppRoute() { |
622 | 625 |
return ( |
623 | 626 |
<Routes> |
627 |
+ |
|
624 | 628 |
<Route path="/Medicalcare" element={<Medicalcare />}></Route> |
625 | 629 |
<Route path="/Healthcare" element={<Healthcare />}></Route> |
626 | 630 |
<Route path="/Join" element={<Join />}></Route> |
627 | 631 |
<Route path="/QuestionSelect" element={<QuestionSelect />}></Route> |
628 | 632 |
|
629 |
- <Route path="/Main_agency" element={<Main_agency />}></Route> |
|
633 |
+ <Route path="/Main" element={<Main_agency />}></Route> |
|
630 | 634 |
<Route path="/UserAuthoriySelect_agency" element={<UserAuthoriySelect_agency />}></Route> |
631 | 635 |
<Route path="/SeniorEdit/:seniorId" element={<SeniorEdit />}></Route> |
632 | 636 |
<Route path="/SeniorSelectOne/:seniorId" element={<SeniorSelectOne />}></Route> |
... | ... | @@ -670,7 +674,7 @@ |
670 | 674 |
const GuardianAppMenuItems = [ |
671 | 675 |
{ |
672 | 676 |
title: "Home", |
673 |
- path: "/Main_guardian", |
|
677 |
+ path: "/Main", |
|
674 | 678 |
icon: <HouseIcon sx={{ fontSize: 20, color: "#333333", marginRight: 1 }} />, |
675 | 679 |
}, |
676 | 680 |
{ |
... | ... | @@ -691,8 +695,8 @@ |
691 | 695 |
function GuardianAppRoute() { |
692 | 696 |
return ( |
693 | 697 |
<Routes> |
694 |
- <Route path="/GuardianStatistics" element={<GuardianStatistics />}></Route> |
|
695 |
- <Route path="/Main_guardian" element={<Main_guardian />}></Route> |
|
698 |
+ <Route path="/GuardianStatistics" element={<GuardianStatistics />}></Route> |
|
699 |
+ <Route path="/Main" element={<Main_guardian />}></Route> |
|
696 | 700 |
<Route path="/QuestionSelect" element={<QuestionSelect />}></Route> |
697 | 701 |
<Route path="/QuestionConfirm/:qnaIdx" element={<QuestionConfirm />}></Route> |
698 | 702 |
|
+++ client/views/pages/AppStore.jsx
... | ... | @@ -0,0 +1,24 @@ |
1 | +import { configureStore, createSlice } from "@reduxjs/toolkit"; | |
2 | + | |
3 | +//로그인 정보 | |
4 | +const loginUser = createSlice({ | |
5 | + name: 'createSlice', | |
6 | + initialState: {}, | |
7 | + reducers: { | |
8 | + setLoginUser(stats, action) { | |
9 | + for (let key in action.payload) { | |
10 | + stats[key] = action.payload[key]; | |
11 | + } | |
12 | + } | |
13 | + } | |
14 | +}) | |
15 | +//로그인 정보 변경 | |
16 | +const { setLoginUser } = loginUser.actions; | |
17 | + | |
18 | +export default configureStore({ | |
19 | + reducer: { | |
20 | + loginUser: loginUser.reducer, | |
21 | + } | |
22 | +}) | |
23 | + | |
24 | +export { setLoginUser };(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/join/Join.jsx
+++ client/views/pages/join/Join.jsx
... | ... | @@ -1,124 +1,359 @@ |
1 | 1 |
import React from "react"; |
2 | 2 |
import Button from "../../component/Button.jsx"; |
3 |
-import { useNavigate } from "react-router"; |
|
3 |
+import { useNavigate, useLocation } from "react-router"; |
|
4 |
+import { useSelector } from "react-redux"; |
|
5 |
+ |
|
6 |
+import CommonUtil from "../../../resources/js/CommonUtil.js"; |
|
7 |
+ |
|
4 | 8 |
export default function Join() { |
5 | 9 |
const navigate = useNavigate(); |
10 |
+ const location = useLocation(); |
|
11 |
+ const defaultAuthority = CommonUtil.isEmpty(location.state) ? null : location.state['authority']; |
|
12 |
+ const defaultAgencyId = CommonUtil.isEmpty(location.state) ? null : location.state['agency_id']; |
|
13 |
+ const defaultGovernmentId = CommonUtil.isEmpty(location.state) ? null :location.state['government_id']; |
|
14 |
+ |
|
15 |
+ |
|
16 |
+ |
|
17 |
+ /**** 기본 조회 데이터 (시작) ****/ |
|
18 |
+ //전역 변수 저장 객체 |
|
19 |
+ const state = useSelector((state) => {return state}); |
|
20 |
+ |
|
21 |
+ //권한 타입 종류 |
|
22 |
+ const [authorities, setAuthorities] = React.useState([]); |
|
23 |
+ //권한 타입 종류 목록 조회 |
|
24 |
+ const authoritiesSelect = () => { |
|
25 |
+ fetch("/common/systemCode/authoritiesSelect.json", { |
|
26 |
+ method: "POST", |
|
27 |
+ headers: { |
|
28 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
29 |
+ }, |
|
30 |
+ body: JSON.stringify({}), |
|
31 |
+ }).then((response) => response.json()).then((data) => { |
|
32 |
+ console.log("권한 타입 종류 목록 조회 : ", data); |
|
33 |
+ setAuthorities(data); |
|
34 |
+ }).catch((error) => { |
|
35 |
+ console.log('authoritiesSelect() /common/systemCode/authoritiesSelect.json error : ', error); |
|
36 |
+ }); |
|
37 |
+ }; |
|
38 |
+ //기관 계층 구조 목록 |
|
39 |
+ const [orgListOfHierarchy, setOrgListOfHierarchy] = React.useState([]); |
|
40 |
+ //기관(관리, 시행) 계층 구조 목록 조회 |
|
41 |
+ const orgSelectListOfHierarchy = () => { |
|
42 |
+ fetch("/org/orgSelectListOfHierarchy.json", { |
|
43 |
+ method: "POST", |
|
44 |
+ headers: { |
|
45 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
46 |
+ }, |
|
47 |
+ body: JSON.stringify({}), |
|
48 |
+ }).then((response) => response.json()).then((data) => { |
|
49 |
+ console.log("기관(관리, 시행) 계층 구조 목록 조회 : ", data); |
|
50 |
+ setOrgListOfHierarchy(data); |
|
51 |
+ }).catch((error) => { |
|
52 |
+ console.log('orgSelectListOfHierarchy() /org/orgSelectListOfHierarchy.json error : ', error); |
|
53 |
+ }); |
|
54 |
+ }; |
|
55 |
+ const getAgencyList = () => { |
|
56 |
+ const government = orgListOfHierarchy.find(item => item['government_id'] == user['government_id']); |
|
57 |
+ if (CommonUtil.isEmpty(government) || CommonUtil.isEmpty(government['agencyList'])) { |
|
58 |
+ return []; |
|
59 |
+ } else { |
|
60 |
+ return government['agencyList']; |
|
61 |
+ } |
|
62 |
+ } |
|
63 |
+ /**** 기본 조회 데이터 (종료) ****/ |
|
64 |
+ |
|
65 |
+ //로그인 중복 확인 |
|
66 |
+ const [isIdCheck, setIsIdCheck] = React.useState(false); |
|
67 |
+ |
|
68 |
+ //등록할 사용자 정보 |
|
69 |
+ const [user, setUser] = React.useState({ |
|
70 |
+ 'user_id': null, |
|
71 |
+ 'user_name': null, |
|
72 |
+ 'user_password': null, |
|
73 |
+ 'user_password_check': null, |
|
74 |
+ 'user_phonenumber': null, |
|
75 |
+ 'user_birth': null, |
|
76 |
+ 'user_gender': null, |
|
77 |
+ 'user_address': null, |
|
78 |
+ 'user_email': null, |
|
79 |
+ 'authority': CommonUtil.isEmpty(defaultAuthority) ? state.loginUser['authority'] : defaultAuthority, |
|
80 |
+ 'agency_id': CommonUtil.isEmpty(defaultAgencyId) ? state.loginUser['agency_id'] : defaultAgencyId, |
|
81 |
+ 'government_id': CommonUtil.isEmpty(defaultGovernmentId) ? state.loginUser['government_id'] : defaultGovernmentId, |
|
82 |
+ }); |
|
83 |
+ //각 데이터별로 Dom 정보 담을 Ref 생성 |
|
84 |
+ const userRefInit = JSON.parse(JSON.stringify(user)); |
|
85 |
+ userRefInit['user_gender'] = {}; |
|
86 |
+ userRefInit['user_id_check_button'] = null; |
|
87 |
+ const userRef = React.useRef(userRefInit); |
|
88 |
+ |
|
89 |
+ //등록할 사용자 정보 변경 |
|
90 |
+ const userValueChange = (targetKey, value) => { |
|
91 |
+ let newUser = JSON.parse(JSON.stringify(user)); |
|
92 |
+ newUser[targetKey] = value; |
|
93 |
+ setUser(newUser); |
|
94 |
+ } |
|
95 |
+ //등록할 사용자의 권한 구분 변경 |
|
96 |
+ const userAuthorityChange = (value) => { |
|
97 |
+ let newUser = JSON.parse(JSON.stringify(user)); |
|
98 |
+ newUser['authority'] = value; |
|
99 |
+ newUser['government_id'] = null; |
|
100 |
+ newUser['agency_id'] = null; |
|
101 |
+ setUser(newUser); |
|
102 |
+ } |
|
103 |
+ //등록할 사용자의 관리기관 변경 |
|
104 |
+ const userGovernmentIdChange = (value) => { |
|
105 |
+ let newUser = JSON.parse(JSON.stringify(user)); |
|
106 |
+ if (CommonUtil.isEmpty(value) == true) { |
|
107 |
+ newUser['government_id'] = null; |
|
108 |
+ } else { |
|
109 |
+ newUser['government_id'] = value; |
|
110 |
+ } |
|
111 |
+ newUser['agency_id'] = null; |
|
112 |
+ setUser(newUser); |
|
113 |
+ } |
|
114 |
+ //등록할 사용자의 시행기관 변경 |
|
115 |
+ const userAgencyIdChange = (value) => { |
|
116 |
+ let newUser = JSON.parse(JSON.stringify(user)); |
|
117 |
+ if (CommonUtil.isEmpty(value) == true) { |
|
118 |
+ newUser['agency_id'] = null; |
|
119 |
+ } else { |
|
120 |
+ newUser['agency_id'] = value; |
|
121 |
+ } |
|
122 |
+ setUser(newUser); |
|
123 |
+ } |
|
124 |
+ //로그인 아이디 중복 검사 |
|
125 |
+ const userIdCheck = () => { |
|
126 |
+ fetch("/user/userSelectOne.json", { |
|
127 |
+ method: "POST", |
|
128 |
+ headers: { |
|
129 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
130 |
+ }, |
|
131 |
+ body: JSON.stringify(user), |
|
132 |
+ }).then((response) => response.json()).then((data) => { |
|
133 |
+ console.log("로그인 아이디 중복 검사(아이디를 통한 사용자 조회) : ", data); |
|
134 |
+ if (CommonUtil.isEmpty(data) == true) { |
|
135 |
+ setIsIdCheck(true); |
|
136 |
+ userRef.current['user_password'].focus(); |
|
137 |
+ alert("사용가능한 아이디 입니다."); |
|
138 |
+ } else { |
|
139 |
+ setIsIdCheck(false); |
|
140 |
+ userRef.current['user_id'].focus(); |
|
141 |
+ alert("이미 존재하는 아이디 입니다."); |
|
142 |
+ } |
|
143 |
+ }).catch((error) => { |
|
144 |
+ console.log('userIdCheck() /user/userSelectOne.json error : ', error); |
|
145 |
+ }); |
|
146 |
+ } |
|
147 |
+ |
|
148 |
+ |
|
149 |
+ //사용자 등록 유효성 검사 |
|
150 |
+ const userInsertValidation = () => { |
|
151 |
+ if ((user['authority'] == 'ROLE_GOVERNMENT' || user['authority'] == 'ROLE_AGENCY') |
|
152 |
+ && CommonUtil.isEmpty(user['government_id']) == true) { |
|
153 |
+ userRef.current['government_id'].focus(); |
|
154 |
+ alert("관리기관을 선택해 주세요."); |
|
155 |
+ return false; |
|
156 |
+ } |
|
157 |
+ |
|
158 |
+ if (user['authority'] == 'ROLE_AGENCY' && CommonUtil.isEmpty(user['agency_id']) == true) { |
|
159 |
+ userRef.current['agency_id'].focus(); |
|
160 |
+ alert("시행기관을 선택해 주세요."); |
|
161 |
+ return false; |
|
162 |
+ } |
|
163 |
+ |
|
164 |
+ if (CommonUtil.isEmpty(user['user_name']) == true) { |
|
165 |
+ userRef.current['user_name'].focus(); |
|
166 |
+ alert("이름을 입력해 주세요."); |
|
167 |
+ return false; |
|
168 |
+ } |
|
169 |
+ if (CommonUtil.isEmpty(user['user_id']) == true) { |
|
170 |
+ userRef.current['user_id'].focus(); |
|
171 |
+ alert("아이디를 입력해 주세요."); |
|
172 |
+ return false; |
|
173 |
+ } |
|
174 |
+ if (isIdCheck == false) { |
|
175 |
+ alert("아이디 중복 확인을 해주세요."); |
|
176 |
+ return false; |
|
177 |
+ } |
|
178 |
+ if (CommonUtil.isEmpty(user['user_password']) == true) { |
|
179 |
+ userRef.current['user_password'].focus(); |
|
180 |
+ alert("비밀번호를 입력해 주세요."); |
|
181 |
+ return false; |
|
182 |
+ } |
|
183 |
+ if (user['user_password'] != user['user_password_check']) { |
|
184 |
+ userRef.current['user_password_check'].focus(); |
|
185 |
+ alert("비밀번호가 일치하지 않습니다."); |
|
186 |
+ return false; |
|
187 |
+ } |
|
188 |
+ if (CommonUtil.isEmpty(user['user_phonenumber']) == true) { |
|
189 |
+ userRef.current['user_phonenumber'].focus(); |
|
190 |
+ alert("연락처를 입력해 주세요."); |
|
191 |
+ return false; |
|
192 |
+ } |
|
193 |
+ |
|
194 |
+ /* if (CommonUtil.isEmpty(user['user_email']) == true) { |
|
195 |
+ userRef.current['user_email'].focus(); |
|
196 |
+ alert("이메일을 입력해 주세요."); |
|
197 |
+ return false; |
|
198 |
+ } */ |
|
199 |
+ |
|
200 |
+ return true; |
|
201 |
+ } |
|
202 |
+ |
|
203 |
+ //사용자 등록 |
|
204 |
+ const userInsert = () => { |
|
205 |
+ if (userInsertValidation() == false) { |
|
206 |
+ return; |
|
207 |
+ } |
|
208 |
+ |
|
209 |
+ fetch("/user/userInsert.json", { |
|
210 |
+ method: "POST", |
|
211 |
+ headers: { |
|
212 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
213 |
+ }, |
|
214 |
+ body: JSON.stringify(user), |
|
215 |
+ }).then((response) => response.json()).then((data) => { |
|
216 |
+ console.log("사용자 등록 결과(건수) : ", data); |
|
217 |
+ if (data > 0) { |
|
218 |
+ alert("계정생성완료"); |
|
219 |
+ navigate(-1); |
|
220 |
+ } else { |
|
221 |
+ alert("계정생성에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
222 |
+ } |
|
223 |
+ }).catch((error) => { |
|
224 |
+ console.log('userInsert() /user/userInsert.json error : ', error); |
|
225 |
+ }); |
|
226 |
+ } |
|
227 |
+ |
|
228 |
+ //Mounted |
|
229 |
+ React.useEffect(() => { |
|
230 |
+ authoritiesSelect(); |
|
231 |
+ orgSelectListOfHierarchy(); |
|
232 |
+ }, []); |
|
233 |
+ |
|
234 |
+ |
|
6 | 235 |
return ( |
7 | 236 |
<div className="container row flex-center join-login"> |
8 | 237 |
<div className="join-group"> |
9 | 238 |
<h3>계정생성</h3> |
10 | 239 |
<div className="join-inner"> |
11 |
- {/* <div> |
|
240 |
+ <div> |
|
12 | 241 |
<div className="flex-start margin-bottom2"> |
13 |
- <label className="flex25">구분</label> |
|
14 |
- <select name="division" id="section"> |
|
15 |
- <option value="manager">관리자</option> |
|
16 |
- <option value="individual">개인</option> |
|
17 |
- <option value="protection_agency">보호기관</option> |
|
18 |
- <option value="hospital">병원</option> |
|
19 |
- <option value="government">지자체</option> |
|
242 |
+ <label className="flex25"><span style={{color : "red"}}>*</span>사용자구분</label> |
|
243 |
+ <select name="division" id="section" onChange={(e) => {userAuthorityChange(e.target.value)}}> |
|
244 |
+ <option value="ROLE_ADMIN" selected={user['authority'] == "ROLE_ADMIN"}>시스템 관리자</option> |
|
245 |
+ <option value="ROLE_GOVERNMENT" selected={user['authority'] == "ROLE_GOVERNMENT"}>기관 관리자</option> |
|
246 |
+ <option value="ROLE_AGENCY" selected={user['authority'] == "ROLE_AGENCY"}>보호사</option> |
|
20 | 247 |
</select> |
21 | 248 |
</div> |
22 |
- </div> */} |
|
249 |
+ </div> |
|
250 |
+ |
|
251 |
+ {user['authority'] == 'ROLE_GOVERNMENT' || user['authority'] == 'ROLE_AGENCY' ? |
|
252 |
+ <div> |
|
253 |
+ <div className="flex-start margin-bottom2"> |
|
254 |
+ <label className="flex25" htmlFor="name"><span style={{color : "red"}}>*</span>관리기관</label> |
|
255 |
+ <select onChange={(e) => {userGovernmentIdChange(e.target.value)}} ref={el => userRef.current['government_id'] = el}> |
|
256 |
+ <option value={''} selected={user['government_id'] == null}>관리기관선택</option> |
|
257 |
+ {orgListOfHierarchy.map((item, idx) => { return ( |
|
258 |
+ <option key={idx} value={item['government_id']} selected={user['government_id'] == item['government_id']}> |
|
259 |
+ {item['government_name']} |
|
260 |
+ </option> |
|
261 |
+ )})} |
|
262 |
+ </select> |
|
263 |
+ </div> |
|
264 |
+ </div> |
|
265 |
+ : null} |
|
266 |
+ |
|
267 |
+ {user['authority'] == 'ROLE_AGENCY' ? |
|
268 |
+ <div> |
|
269 |
+ <div className="flex-start margin-bottom2"> |
|
270 |
+ <label className="flex25" htmlFor="name"><span style={{color : "red"}}>*</span>시행기관</label> |
|
271 |
+ <select onChange={(e) => {userAgencyIdChange(e.target.value)}} ref={el => userRef.current['agency_id'] = el}> |
|
272 |
+ <option value={''} selected={user['agency_id'] == null}>시행기관선택</option> |
|
273 |
+ {getAgencyList().map((item, idx) => { return ( |
|
274 |
+ <option key={idx} value={item['agency_id']} selected={user['agency_id'] == item['agency_id']}> |
|
275 |
+ {item['agency_name']} |
|
276 |
+ </option> |
|
277 |
+ )})} |
|
278 |
+ </select> |
|
279 |
+ </div> |
|
280 |
+ </div> |
|
281 |
+ : null} |
|
282 |
+ |
|
23 | 283 |
<div> |
24 | 284 |
<div className="flex-start margin-bottom2"> |
25 |
- <label className="flex25" htmlFor="name"> |
|
26 |
- 기관명 |
|
27 |
- </label> |
|
28 |
- <input |
|
29 |
- type="text" |
|
30 |
- name="name" |
|
31 |
- placeholder="" |
|
32 |
- autocomplete="off" |
|
33 |
- id="name" |
|
285 |
+ <label className="flex25" htmlFor="name"><span style={{color : "red"}}>*</span>이름</label> |
|
286 |
+ <input type="text" |
|
287 |
+ value={user['user_name']} |
|
288 |
+ onChange={(e) => {userValueChange('user_name', e.target.value)}} |
|
289 |
+ ref={el => userRef.current['user_name'] = el} |
|
34 | 290 |
/> |
35 | 291 |
</div> |
36 | 292 |
</div> |
37 |
- <div> |
|
38 |
- <div className="flex-start margin-bottom2"> |
|
39 |
- <label className="flex25" htmlFor="name"> |
|
40 |
- 이름 |
|
41 |
- </label> |
|
42 |
- <input |
|
43 |
- type="text" |
|
44 |
- name="name" |
|
45 |
- placeholder="" |
|
46 |
- autocomplete="off" |
|
47 |
- id="name" |
|
48 |
- /> |
|
49 |
- </div> |
|
50 |
- </div> |
|
293 |
+ |
|
51 | 294 |
<div className="id"> |
52 | 295 |
<div className="flex-start margin-bottom2"> |
53 |
- <label className="flex25" htmlFor="id"> |
|
54 |
- 아이디 |
|
55 |
- </label> |
|
56 |
- <input |
|
57 |
- type="text" |
|
58 |
- name="id" |
|
59 |
- placeholder="" |
|
60 |
- autocomplete="off" |
|
61 |
- id="id" |
|
296 |
+ <label className="flex25" htmlFor="id"><span style={{color : "red"}}>*</span>아이디</label> |
|
297 |
+ <input type="text" |
|
298 |
+ value={user['user_id']} |
|
299 |
+ onChange={(e) => {userValueChange('user_id', e.target.value); setIsIdCheck(false)}} |
|
300 |
+ ref={el => userRef.current['user_id'] = el} |
|
62 | 301 |
/> |
63 |
- <Button |
|
64 |
- btnName={"중복확인"} |
|
65 |
- className={"red-btn btn-large"} |
|
66 |
- onclick="openIdChk()" |
|
302 |
+ <button className={"red-btn btn-large"} onClick={userIdCheck} |
|
303 |
+ ref={el => userRef.current['user_id_check_button'] = el}> |
|
304 |
+ 중복확인 |
|
305 |
+ </button> |
|
306 |
+ </div> |
|
307 |
+ </div> |
|
308 |
+ |
|
309 |
+ <div> |
|
310 |
+ <div className="flex-start margin-bottom2"> |
|
311 |
+ <label className="flex25" htmlFor="password"><span style={{color : "red"}}>*</span>비밀번호</label> |
|
312 |
+ <input type="password" |
|
313 |
+ value={user['user_password']} |
|
314 |
+ onChange={(e) => {userValueChange('user_password', e.target.value)}} |
|
315 |
+ ref={el => userRef.current['user_password'] = el} |
|
67 | 316 |
/> |
68 | 317 |
</div> |
69 | 318 |
</div> |
70 | 319 |
<div> |
71 | 320 |
<div className="flex-start margin-bottom2"> |
72 |
- <label className="flex25" htmlFor="password"> |
|
73 |
- 비밀번호 |
|
74 |
- </label> |
|
75 |
- <input |
|
76 |
- type="text" |
|
77 |
- name="password" |
|
78 |
- placeholder="" |
|
79 |
- autocomplete="off" |
|
80 |
- id="password" |
|
321 |
+ <label className="flex25" htmlFor="password_check"><span style={{color : "red"}}>*</span>비밀번호 확인</label> |
|
322 |
+ <input type="password" |
|
323 |
+ value={user['user_password_check']} |
|
324 |
+ onChange={(e) => {userValueChange('user_password_check', e.target.value)}} |
|
325 |
+ ref={el => userRef.current['user_password_check'] = el} |
|
81 | 326 |
/> |
82 | 327 |
</div> |
83 | 328 |
</div> |
84 |
- <div> |
|
85 |
- <div className="flex-start margin-bottom2"> |
|
86 |
- <label className="flex25" htmlFor="password_check"> |
|
87 |
- 비밀번호 확인 |
|
88 |
- </label> |
|
89 |
- <input |
|
90 |
- type="text" |
|
91 |
- name="password_check" |
|
92 |
- placeholder="" |
|
93 |
- autocomplete="off" |
|
94 |
- id="password_check" |
|
95 |
- /> |
|
96 |
- </div> |
|
97 |
- </div> |
|
329 |
+ |
|
98 | 330 |
<div> |
99 | 331 |
<div className="flex margin-bottom2"> |
100 |
- <label className="flex25" htmlFor="phone_number"> |
|
101 |
- 전화번호 |
|
102 |
- </label> |
|
103 |
- <input |
|
104 |
- type="text" |
|
105 |
- name="phone_number" |
|
106 |
- placeholder="" |
|
107 |
- autocomplete="off" |
|
108 |
- id="phone_number" |
|
332 |
+ <label className="flex25" htmlFor="phone_number"><span style={{color : "red"}}>*</span>전화번호</label> |
|
333 |
+ <input type="number" maxLength="11" |
|
334 |
+ value={user['user_phonenumber']} |
|
335 |
+ onChange={(e) => {userValueChange('user_phonenumber', e.target.value)}} |
|
336 |
+ ref={el => userRef.current['user_phonenumber'] = el} |
|
109 | 337 |
/> |
110 | 338 |
</div> |
111 | 339 |
</div> |
112 |
- <div className="btn-wrap"> |
|
113 |
- <Button className={"gray-btn btn-large"} btnName={"취소"} /> |
|
114 |
- <Button |
|
115 |
- className={"red-btn btn-large"} |
|
116 |
- btnName={"등록"} |
|
117 |
- onClick={() => { |
|
118 |
- navigate("Login"); |
|
119 |
- }} |
|
120 |
- /> |
|
340 |
+ |
|
341 |
+ <div> |
|
342 |
+ <div className="flex-start margin-bottom2"> |
|
343 |
+ <label className="flex25" htmlFor="password_check">이메일</label> |
|
344 |
+ <input type="text" |
|
345 |
+ value={user['user_email']} |
|
346 |
+ onChange={(e) => {userValueChange('user_email', e.target.value)}} |
|
347 |
+ ref={el => userRef.current['user_email'] = el} |
|
348 |
+ /> |
|
349 |
+ </div> |
|
121 | 350 |
</div> |
351 |
+ |
|
352 |
+ <div className="btn-wrap"> |
|
353 |
+ <button className={"gray-btn btn-large"} onClick={() => {navigate(-1)}}>취소</button> |
|
354 |
+ <button className={"red-btn btn-large"} onClick={userInsert}>등록</button> |
|
355 |
+ </div> |
|
356 |
+ |
|
122 | 357 |
</div> |
123 | 358 |
</div> |
124 | 359 |
</div> |
--- client/views/pages/login/Login.jsx
+++ client/views/pages/login/Login.jsx
... | ... | @@ -1,22 +1,57 @@ |
1 | 1 |
import React from "react"; |
2 |
-import Button from "../../component/Button.jsx"; |
|
3 |
-import Join from "./../join/Join.jsx"; |
|
2 |
+import { useNavigate, useLocation } from "react-router"; |
|
4 | 3 |
|
5 |
-export default function Login({ getLogin }) { |
|
6 |
- const [isJoin, setIsJoin] = React.useState(false); |
|
7 |
- const onClickJoin = () => { |
|
8 |
- setIsJoin(true); |
|
9 |
- console.log(isJoin); |
|
4 |
+ |
|
5 |
+import Join from "./../join/Join.jsx"; |
|
6 |
+import Button from "../../component/Button.jsx"; |
|
7 |
+ |
|
8 |
+ |
|
9 |
+export default function Login() { |
|
10 |
+ const navigate = useNavigate(); |
|
11 |
+ const location = useLocation(); |
|
12 |
+ |
|
13 |
+ //로그인 정보 |
|
14 |
+ const [loginInfo, setLoginInfo] = React.useState({'user_id': '', 'user_password': ''}); |
|
15 |
+ //사용자의 입력으로 인한 로그인 정보 변경 |
|
16 |
+ const loginInfoChange = (key, value) => { |
|
17 |
+ let newLoginInfo = JSON.parse(JSON.stringify(loginInfo)); |
|
18 |
+ newLoginInfo[key] = value; |
|
19 |
+ setLoginInfo(newLoginInfo); |
|
20 |
+ } |
|
21 |
+ |
|
22 |
+ //로그인 엔터 |
|
23 |
+ const loginEnter = (key) => { |
|
24 |
+ if (key == 'Enter') { |
|
25 |
+ login(); |
|
26 |
+ } else { |
|
27 |
+ return; |
|
28 |
+ } |
|
29 |
+ } |
|
30 |
+ |
|
31 |
+ //로그인 |
|
32 |
+ const login = () => { |
|
33 |
+ fetch("/user/login.json", { |
|
34 |
+ method: "POST", |
|
35 |
+ headers: { |
|
36 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
37 |
+ }, |
|
38 |
+ body: JSON.stringify(loginInfo), |
|
39 |
+ }).then((response) => response.json()).then((data) => { |
|
40 |
+ console.log("로그인 결과 : ", data); |
|
41 |
+ if (data.isSuccess == true) { |
|
42 |
+ navigate('/Main'); |
|
43 |
+ } else { |
|
44 |
+ alert(data.message); |
|
45 |
+ } |
|
46 |
+ }).catch((error) => { |
|
47 |
+ console.log('login() /user/login.json error : ', error); |
|
48 |
+ }); |
|
10 | 49 |
}; |
11 |
- const onClickLogin = () => { |
|
12 |
- getLogin(); |
|
13 |
- }; |
|
50 |
+ |
|
14 | 51 |
return ( |
15 | 52 |
<div className="row login-wrap"> |
16 | 53 |
<h1>시니어 스마트 케어 모니터링 플랫폼</h1> |
17 |
- {isJoin ? ( |
|
18 |
- <Join /> |
|
19 |
- ) : ( |
|
54 |
+ {location.pathname == '/Join' ? (<Join/>) : ( |
|
20 | 55 |
<div className="container row flex-center join-login"> |
21 | 56 |
<div className="login-form"> |
22 | 57 |
<div> |
... | ... | @@ -24,19 +59,18 @@ |
24 | 59 |
<div className="login-inner"> |
25 | 60 |
<div className="content"> |
26 | 61 |
<i className="fa-solid fa-user"></i> |
27 |
- <input |
|
28 |
- required |
|
29 |
- maxlength="15" |
|
30 |
- type="text" |
|
31 |
- placeholder="아이디를 입력하세요" |
|
62 |
+ <input type="text" placeholder="아이디를 입력하세요" |
|
63 |
+ value={loginInfo['user_id']} |
|
64 |
+ onChange={(e) => {loginInfoChange('user_id', e.target.value)}} |
|
65 |
+ onKeyUp={(e) => {loginEnter(e.key)}} |
|
32 | 66 |
/> |
33 | 67 |
</div> |
34 | 68 |
<div className="content"> |
35 | 69 |
<i className="fa-solid fa-lock"></i> |
36 |
- <input |
|
37 |
- type="password" |
|
38 |
- name="password" |
|
39 |
- placeholder="비밀번호를 입력하세요" |
|
70 |
+ <input type="password" placeholder="비밀번호를 입력하세요" |
|
71 |
+ value={loginInfo['user_password']} |
|
72 |
+ onChange={(e) => {loginInfoChange('user_password', e.target.value)}} |
|
73 |
+ onKeyUp={(e) => {loginEnter(e.key)}} |
|
40 | 74 |
/> |
41 | 75 |
</div> |
42 | 76 |
</div> |
... | ... | @@ -45,13 +79,13 @@ |
45 | 79 |
<Button |
46 | 80 |
className={"btn-100 green-btn"} |
47 | 81 |
btnName={"로그인"} |
48 |
- onClick={onClickLogin} |
|
82 |
+ onClick={login} |
|
49 | 83 |
/> |
50 | 84 |
<div className="flex-center btn-bottom"> |
51 | 85 |
<Button |
52 | 86 |
className={"join-btn"} |
53 | 87 |
btnName={"회원가입"} |
54 |
- onClick={onClickJoin} |
|
88 |
+ onClick={() => {navigate('/Join')}} |
|
55 | 89 |
/> |
56 | 90 |
</div> |
57 | 91 |
</div> |
--- client/views/pages/user_management/UserAuthoriySelect.jsx
+++ client/views/pages/user_management/UserAuthoriySelect.jsx
... | ... | @@ -1,5 +1,7 @@ |
1 | 1 |
import React, { useState } from "react"; |
2 | 2 |
import { useNavigate } from "react-router"; |
3 |
+import { useSelector } from "react-redux"; |
|
4 |
+ |
|
3 | 5 |
import ContentTitle from "../../component/ContentTitle.jsx"; |
4 | 6 |
import SubTitle from "../../component/SubTitle.jsx"; |
5 | 7 |
import Modal from "../../component/Modal.jsx"; |
... | ... | @@ -9,333 +11,634 @@ |
9 | 11 |
import Modal_SeniorInsert from "../../component/Modal_SeniorInsert.jsx"; |
10 | 12 |
import { width } from "@mui/system"; |
11 | 13 |
import Modal_Guardian from "../../component/Modal_Guardian.jsx"; |
14 |
+import Pagination from "../../component/Pagination.jsx"; |
|
15 |
+ |
|
16 |
+import CommonUtil from "../../../resources/js/CommonUtil.js"; |
|
12 | 17 |
|
13 | 18 |
export default function UserAuthoriySelect() { |
14 | 19 |
const navigate = useNavigate(); |
15 |
- const [agencyName, setAgencyName] = useState("시행기관") |
|
16 |
- const [modalOpen, setModalOpen] = React.useState(false); |
|
17 |
- const openModal = () => { |
|
18 |
- setModalOpen(true); |
|
19 |
- }; |
|
20 |
- const closeModal = () => { |
|
21 |
- setModalOpen(false); |
|
22 |
- }; |
|
23 |
- const [modalOpen2, setModalOpen2] = React.useState(false); |
|
24 |
- const openModal2 = () => { |
|
25 |
- setModalOpen2(true); |
|
26 |
- }; |
|
27 |
- const closeModal2 = () => { |
|
28 |
- setModalOpen2(false); |
|
29 |
- }; |
|
30 |
- const thead = [ |
|
31 |
- "No", |
|
32 |
- "소속기관명", |
|
33 |
- "이름", |
|
34 |
- "연락처", |
|
35 |
- "성별", |
|
36 |
- "주소", |
|
37 |
- "담당 대상자(어르신) 인원", |
|
38 |
- ]; |
|
39 |
- const key = [ |
|
40 |
- "No", |
|
41 |
- "center", |
|
42 |
- "name", |
|
43 |
- "phone", |
|
44 |
- "gender", |
|
45 |
- "address", |
|
46 |
- "worker", |
|
47 |
- ]; |
|
48 |
- const content = [ |
|
49 |
- { |
|
50 |
- No: 1, |
|
51 |
- center: "A복지관", |
|
52 |
- name: "홍길동", |
|
53 |
- phone: "010-1234-1234", |
|
54 |
- gender: "여", |
|
55 |
- address: "경상북도 군위군 삼국유사면", |
|
56 |
- worker: "10명" |
|
57 |
- }, |
|
58 | 20 |
|
59 |
- ]; |
|
21 |
+ //전역 변수 저장 객체 |
|
22 |
+ const state = useSelector((state) => {return state}); |
|
60 | 23 |
|
61 |
- const thead1 = [ |
|
62 |
- "No", |
|
63 |
- "소속기관명", //관리기관 클릭시 보이게 |
|
64 |
- "이름", |
|
65 |
- "대상자등록번호", |
|
66 |
- "생년월일", |
|
67 |
- "성별", |
|
68 |
- "연락처", |
|
69 |
- "주소", |
|
70 |
- "보호자", |
|
71 |
- ]; |
|
72 |
- const key1 = ["No", |
|
73 |
- "name", |
|
74 |
- "center", |
|
75 |
- "management_number", |
|
76 |
- "birth", |
|
77 |
- "gender", |
|
78 |
- "phone", |
|
79 |
- "address", |
|
80 |
- "family", |
|
81 |
- ]; |
|
82 |
- const content1 = [ |
|
83 |
- { |
|
84 |
- No: 1, |
|
85 |
- center: "A복지관", |
|
86 |
- name: "김복남", |
|
87 |
- management_number: 2022080101, |
|
88 |
- birth: "1950.02.03", |
|
89 |
- gender: "남", |
|
90 |
- phone: "010-1234-1234", |
|
91 |
- address: "경상북도 군위군 삼국유사면", |
|
92 |
- family: ( |
|
93 |
- <Button |
|
94 |
- className={"btn-small lightgray-btn"} |
|
95 |
- btnName={"보호자(가족) 보기"} |
|
96 |
- onClick={openModal} |
|
97 |
- /> |
|
98 |
- ), |
|
99 |
- }, |
|
100 |
- ]; |
|
101 |
- const thead3 = [ |
|
102 |
- "No", |
|
103 |
- "사용자명", |
|
104 |
- "사용자ID", |
|
105 |
- "대상자와의 관계", |
|
106 |
- "보호자 연락처", |
|
107 |
- ]; |
|
108 |
- const key3 = [ |
|
109 |
- "No", |
|
110 |
- "name", |
|
111 |
- "Id", |
|
112 |
- "relationship", |
|
113 |
- "phone", |
|
114 |
- ]; |
|
115 |
- const content3 = [ |
|
116 |
- { |
|
117 |
- No: 1, |
|
118 |
- name: "김훈", |
|
119 |
- Id: "admin2", |
|
120 |
- relationship: "아들", |
|
121 |
- phone: "010-1234-1234", |
|
122 |
- }, |
|
123 |
- ]; |
|
124 |
- const data = [ |
|
125 |
- { |
|
126 |
- id: 1, |
|
127 |
- title: "대상자(사용자)", |
|
128 |
- description: ( |
|
129 |
- <div> |
|
130 |
- <div className="search-management flex-start margin-bottom2"> |
|
131 |
- <select> |
|
132 |
- <option value="이름">이름</option> |
|
133 |
- <option value="아이디">사용자등록번호</option> |
|
134 |
- <option value="아이디">ID</option> |
|
135 |
- </select> |
|
136 |
- <input type="text" /> |
|
137 |
- <Button |
|
138 |
- className={"btn-small gray-btn"} |
|
139 |
- btnName={"검색"} |
|
140 |
- onClick={() => navigate("/SeniorInsert")} |
|
141 |
- /> |
|
142 |
- </div> |
|
143 |
- <div className="btn-wrap flex-end margin-bottom"> |
|
144 |
- <Button |
|
145 |
- className={"btn-small gray-btn"} |
|
146 |
- btnName={"등록"} |
|
147 |
- onClick={openModal2} |
|
148 |
- /> |
|
149 |
- <Button className={"btn-small red-btn"} btnName={"삭제"} /> |
|
150 |
- </div> |
|
151 |
- <Table |
|
152 |
- className={"protector-user"} |
|
153 |
- head={thead1} |
|
154 |
- contents={content1} |
|
155 |
- contentKey={key1} |
|
156 |
- onClick={() => { |
|
157 |
- navigate("/SeniorSelectOne"); |
|
158 |
- }} |
|
159 |
- /> |
|
160 |
- </div> |
|
24 |
+ //활성화 탭 (시스템 업무 역할별) |
|
25 |
+ const [tabActiveByRoleType, setTabActiveByRoleType] = React.useState('ROLE_SENIOR'); |
|
161 | 26 |
|
162 |
- ), |
|
163 |
- }, |
|
164 |
- { |
|
165 |
- id: 2, |
|
166 |
- title: "복지사(간호사)", |
|
167 |
- description: ( |
|
168 |
- <div> |
|
169 |
- <div className="search-management flex-start margin-bottom2"> |
|
170 |
- <select> |
|
171 |
- <option value="이름">이름</option> |
|
172 |
- <option value="아이디">사용자등록번호</option> |
|
173 |
- <option value="아이디">ID</option> |
|
174 |
- </select> |
|
175 |
- <input type="text" /> |
|
176 |
- <Button |
|
177 |
- className={"btn-small gray-btn"} |
|
178 |
- btnName={"검색"} |
|
179 |
- onClick={() => navigate("/SeniorInsert")} |
|
180 |
- /> |
|
181 |
- </div> |
|
182 |
- <div className="btn-wrap flex-end margin-bottom"> |
|
183 |
- <Button |
|
184 |
- className={"btn-small gray-btn"} |
|
185 |
- btnName={"등록"} |
|
186 |
- onClick={() => { |
|
187 |
- navigate("/Join"); |
|
188 |
- }} |
|
189 |
- /> |
|
190 |
- <Button className={"btn-small red-btn"} btnName={"삭제"} /> |
|
191 |
- </div> |
|
192 |
- <Table |
|
193 |
- className={"senior-table"} |
|
194 |
- head={thead} |
|
195 |
- contents={content} |
|
196 |
- contentKey={key} |
|
197 |
- onClick={() => { |
|
198 |
- navigate("/SeniorSelectOne"); |
|
199 |
- }} |
|
200 |
- /> |
|
201 |
- </div> |
|
27 |
+ //보호자 모달 오픈 여부 |
|
28 |
+ const [modalGuardianIsOpen, setModalGuardianIsOpen] = React.useState(false); |
|
29 |
+ //보호자 모달 오픈 |
|
30 |
+ const modalGuardianOpen = () => { |
|
31 |
+ setModalGuardianIsOpen(true); |
|
32 |
+ }; |
|
33 |
+ //보호자 모달 닫기 |
|
34 |
+ const modalGuardianClose = () => { |
|
35 |
+ setModalGuardianIsOpen(false); |
|
36 |
+ }; |
|
202 | 37 |
|
203 |
- ), |
|
204 |
- }, |
|
205 |
- { |
|
206 |
- id: 3, |
|
207 |
- title: "기관상세정보", |
|
208 |
- description: ( |
|
209 |
- <div> |
|
210 |
- <table className="agency-detail"> |
|
211 |
- <tbody> |
|
212 |
- <tr> |
|
213 |
- <td>회사명</td> |
|
214 |
- <td>군위군ㅊ청</td> |
|
215 |
- </tr> |
|
216 |
- <tr> |
|
217 |
- <td>주소</td> |
|
218 |
- <td>군위군 군위읍</td> |
|
219 |
- </tr> |
|
220 |
- <tr> |
|
221 |
- <td>담당직원</td> |
|
222 |
- <td>김직원</td> |
|
223 |
- </tr> |
|
224 |
- <tr> |
|
225 |
- <td>전화번호</td> |
|
226 |
- <td>053-855-8555</td> |
|
227 |
- </tr> |
|
228 |
- </tbody> |
|
229 |
- </table> |
|
230 |
- </div> |
|
231 |
- ), |
|
232 |
- }, |
|
233 |
- ] |
|
234 |
- const [index, setIndex] = React.useState(1); |
|
38 |
+ //대상자(시니어) 등록 모달 오픈 여부 |
|
39 |
+ const [modalSeniorInsertIsOpen, setModalSeniorInsertIsOpen] = React.useState(false); |
|
40 |
+ //대상자(시니어) 등록 모달 오픈 |
|
41 |
+ const modalSeniorInsertOpen = () => { |
|
42 |
+ setModalSeniorInsertIsOpen(true); |
|
43 |
+ }; |
|
44 |
+ //대상자(시니어) 등록 모달 닫기 |
|
45 |
+ const modalSeniorInsertClose = () => { |
|
46 |
+ setModalSeniorInsertIsOpen(false); |
|
47 |
+ }; |
|
48 |
+ |
|
49 |
+ //기관 계층 구조 목록 |
|
50 |
+ const [orgListOfHierarchy, setOrgListOfHierarchy] = React.useState([]); |
|
51 |
+ //기관(관리, 시행) 계층 구조 목록 조회 |
|
52 |
+ const orgSelectListOfHierarchy = () => { |
|
53 |
+ fetch("/org/orgSelectListOfHierarchy.json", { |
|
54 |
+ method: "POST", |
|
55 |
+ headers: { |
|
56 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
57 |
+ }, |
|
58 |
+ body: JSON.stringify({}), |
|
59 |
+ }).then((response) => response.json()).then((data) => { |
|
60 |
+ console.log("기관(관리, 시행) 계층 구조 목록 조회 : ", data); |
|
61 |
+ setOrgListOfHierarchy(data); |
|
62 |
+ }).catch((error) => { |
|
63 |
+ console.log('orgSelectListOfHierarchy() /org/orgSelectListOfHierarchy.json error : ', error); |
|
64 |
+ }); |
|
65 |
+ }; |
|
66 |
+ |
|
67 |
+ |
|
68 |
+ |
|
69 |
+ //검색 변수 (초기화값) |
|
70 |
+ const [userSearch, setUserSearch] = React.useState({ |
|
71 |
+ 'government_id': state.loginUser['government_id'], |
|
72 |
+ 'agency_id': state.loginUser['agency_id'], |
|
73 |
+ 'authority': null, |
|
74 |
+ |
|
75 |
+ 'searchType': null, |
|
76 |
+ 'searchText': null, |
|
77 |
+ 'currentPage': 1, |
|
78 |
+ 'perPage': 10, |
|
79 |
+ }); |
|
80 |
+ |
|
81 |
+ //대상자(시니어) 목록 및 페이징 정보 |
|
82 |
+ userSearch['authority'] = 'ROLE_SENIOR'; |
|
83 |
+ const [senior, setSenior] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))}); |
|
84 |
+ const seniorSearchChange = (targetKey, value) => { |
|
85 |
+ let newSenior = JSON.parse(JSON.stringify(senior)); |
|
86 |
+ newSenior.search[targetKey] = value; |
|
87 |
+ setSenior(newSenior); |
|
88 |
+ } |
|
89 |
+ const seniorSelectListEnter = (key) => { |
|
90 |
+ if (key == 'Enter') { |
|
91 |
+ seniorSelectList(); |
|
92 |
+ } else { |
|
93 |
+ return; |
|
94 |
+ } |
|
95 |
+ } |
|
96 |
+ //대상자(시니어) 목록 조회 |
|
97 |
+ const seniorSelectList = (currentPage) => { |
|
98 |
+ senior.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage; |
|
99 |
+ |
|
100 |
+ fetch("/user/userSelectList.json", { |
|
101 |
+ method: "POST", |
|
102 |
+ headers: { |
|
103 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
104 |
+ }, |
|
105 |
+ body: JSON.stringify(senior.search), |
|
106 |
+ }).then((response) => response.json()).then((data) => { |
|
107 |
+ data.search = senior.search; |
|
108 |
+ console.log("대상자(시니어) 목록 조회 : ", data); |
|
109 |
+ setSenior(data); |
|
110 |
+ }).catch((error) => { |
|
111 |
+ console.log('seniorSelectList() /user/userSelectList.json error : ', error); |
|
112 |
+ }); |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ //시행기관 담당자 목록 및 페이징 정보 |
|
116 |
+ userSearch['authority'] = 'ROLE_AGENCY'; |
|
117 |
+ const [agent, setAgent] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))}); |
|
118 |
+ const agentSearchChange = (targetKey, value) => { |
|
119 |
+ let newAgent = JSON.parse(JSON.stringify(agent)); |
|
120 |
+ newAgent.search[targetKey] = value; |
|
121 |
+ setAgent(newAgent); |
|
122 |
+ } |
|
123 |
+ const agentSelectListEnter = (key) => { |
|
124 |
+ if (key == 'Enter') { |
|
125 |
+ agentSelectList(); |
|
126 |
+ } else { |
|
127 |
+ return; |
|
128 |
+ } |
|
129 |
+ } |
|
130 |
+ //시행기관 담당자 목록 조회 |
|
131 |
+ const agentSelectList = (currentPage) => { |
|
132 |
+ agent.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage; |
|
133 |
+ |
|
134 |
+ fetch("/user/userSelectList.json", { |
|
135 |
+ method: "POST", |
|
136 |
+ headers: { |
|
137 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
138 |
+ }, |
|
139 |
+ body: JSON.stringify(agent.search), |
|
140 |
+ }).then((response) => response.json()).then((data) => { |
|
141 |
+ data.search = agent.search; |
|
142 |
+ console.log("시행기관 담당자 목록 조회 : ", data); |
|
143 |
+ setAgent(data); |
|
144 |
+ }).catch((error) => { |
|
145 |
+ console.log('agentSelectList() /user/userSelectList.json error : ', error); |
|
146 |
+ }); |
|
147 |
+ } |
|
148 |
+ |
|
149 |
+ //관리기관 관리자 목록 및 페이징 정보 |
|
150 |
+ userSearch['authority'] = 'ROLE_GOVERNMENT'; |
|
151 |
+ const [government, setGovernment] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))}); |
|
152 |
+ const governmentSearchChange = (targetKey, value) => { |
|
153 |
+ let newGovernment = JSON.parse(JSON.stringify(government)); |
|
154 |
+ newGovernment.search[targetKey] = value; |
|
155 |
+ setGovernment(newGovernment); |
|
156 |
+ } |
|
157 |
+ const governmentSelectListEnter = (key) => { |
|
158 |
+ if (key == 'Enter') { |
|
159 |
+ governmentSelectList(); |
|
160 |
+ } else { |
|
161 |
+ return; |
|
162 |
+ } |
|
163 |
+ } |
|
164 |
+ //관리기관 담당자 목록 조회 |
|
165 |
+ const governmentSelectList = (currentPage) => { |
|
166 |
+ government.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage; |
|
167 |
+ |
|
168 |
+ fetch("/user/userSelectList.json", { |
|
169 |
+ method: "POST", |
|
170 |
+ headers: { |
|
171 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
172 |
+ }, |
|
173 |
+ body: JSON.stringify(government.search), |
|
174 |
+ }).then((response) => response.json()).then((data) => { |
|
175 |
+ data.search = government.search; |
|
176 |
+ console.log("관리기관 담당자 목록 조회 : ", data); |
|
177 |
+ setGovernment(data); |
|
178 |
+ }).catch((error) => { |
|
179 |
+ console.log('governmentSelectList() /user/userSelectList.json error : ', error); |
|
180 |
+ }); |
|
181 |
+ } |
|
182 |
+ |
|
183 |
+ //시스템 관리자 목록 및 페이징 정보 |
|
184 |
+ userSearch['authority'] = 'ROLE_ADMIN'; |
|
185 |
+ const [admin, setAdmin] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))}); |
|
186 |
+ const adminSearchChange = (targetKey, value) => { |
|
187 |
+ let newAdmin = JSON.parse(JSON.stringify(admin)); |
|
188 |
+ newAdmin.search[targetKey] = value; |
|
189 |
+ setAdmin(newAdmin); |
|
190 |
+ } |
|
191 |
+ const adminSelectListEnter = (key) => { |
|
192 |
+ if (key == 'Enter') { |
|
193 |
+ adminSelectList(); |
|
194 |
+ } else { |
|
195 |
+ return; |
|
196 |
+ } |
|
197 |
+ } |
|
198 |
+ //시스템 관리자 목록 조회 |
|
199 |
+ const adminSelectList = (currentPage) => { |
|
200 |
+ admin.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage; |
|
201 |
+ |
|
202 |
+ fetch("/user/userSelectList.json", { |
|
203 |
+ method: "POST", |
|
204 |
+ headers: { |
|
205 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
206 |
+ }, |
|
207 |
+ body: JSON.stringify(admin.search), |
|
208 |
+ }).then((response) => response.json()).then((data) => { |
|
209 |
+ data.search = admin.search; |
|
210 |
+ console.log("시스템 관리자 목록 조회 : ", data); |
|
211 |
+ setAdmin(data); |
|
212 |
+ }).catch((error) => { |
|
213 |
+ console.log('adminSelectList() /user/userSelectList.json error : ', error); |
|
214 |
+ }); |
|
215 |
+ } |
|
216 |
+ |
|
217 |
+ |
|
218 |
+ //올잇메디 선택 |
|
219 |
+ const adminChange = () => { |
|
220 |
+ const newUserSearch = JSON.parse(JSON.stringify(userSearch)); |
|
221 |
+ newUserSearch['government_id'] = null; |
|
222 |
+ newUserSearch['agency_id'] = null; |
|
223 |
+ setUserSearch(newUserSearch); |
|
224 |
+ |
|
225 |
+ senior.search['government_id'] = null; |
|
226 |
+ senior.search['agency_id'] = null; |
|
227 |
+ seniorSelectList(); |
|
228 |
+ agent.search['government_id'] = null; |
|
229 |
+ agent.search['agency_id'] = null; |
|
230 |
+ agentSelectList(); |
|
231 |
+ if (state.loginUser['authority'] == 'ROLE_ADMIN' || state.loginUser['authority'] == 'ROLE_GOVERNMENT') { |
|
232 |
+ government.search['government_id'] = null; |
|
233 |
+ government.search['agency_id'] = null; |
|
234 |
+ governmentSelectList(); |
|
235 |
+ } |
|
236 |
+ } |
|
237 |
+ |
|
238 |
+ //관리 기관 선택 |
|
239 |
+ const governmentChange = (government_id) => { |
|
240 |
+ const newUserSearch = JSON.parse(JSON.stringify(userSearch)); |
|
241 |
+ newUserSearch['government_id'] = government_id; |
|
242 |
+ newUserSearch['agency_id'] = null; |
|
243 |
+ setUserSearch(newUserSearch); |
|
244 |
+ |
|
245 |
+ senior.search['government_id'] = government_id; |
|
246 |
+ senior.search['agency_id'] = null; |
|
247 |
+ seniorSelectList(); |
|
248 |
+ agent.search['government_id'] = government_id; |
|
249 |
+ agent.search['agency_id'] = null; |
|
250 |
+ agentSelectList(); |
|
251 |
+ if (state.loginUser['authority'] == 'ROLE_ADMIN' || state.loginUser['authority'] == 'ROLE_GOVERNMENT') { |
|
252 |
+ government.search['government_id'] = government_id; |
|
253 |
+ government.search['agency_id'] = null; |
|
254 |
+ governmentSelectList(); |
|
255 |
+ } |
|
256 |
+ } |
|
257 |
+ |
|
258 |
+ //시행 기관 선택 |
|
259 |
+ const agencyChange = (government_id, agency_id) => { |
|
260 |
+ const newUserSearch = JSON.parse(JSON.stringify(userSearch)); |
|
261 |
+ newUserSearch['government_id'] = government_id; |
|
262 |
+ newUserSearch['agency_id'] = agency_id; |
|
263 |
+ setUserSearch(newUserSearch); |
|
264 |
+ |
|
265 |
+ senior.search['government_id'] = government_id; |
|
266 |
+ senior.search['agency_id'] = agency_id; |
|
267 |
+ console.log('senior.search : ', senior.search); |
|
268 |
+ seniorSelectList(); |
|
269 |
+ agent.search['government_id'] = government_id; |
|
270 |
+ agent.search['agency_id'] = agency_id; |
|
271 |
+ agentSelectList(); |
|
272 |
+ } |
|
273 |
+ |
|
274 |
+ |
|
275 |
+ |
|
276 |
+ //사용자 등록 페이지 이동 |
|
277 |
+ const join = () => { |
|
278 |
+ console.log('userSearch : ', userSearch); |
|
279 |
+ navigate("/Join", {state: { |
|
280 |
+ 'government_id': userSearch['government_id'], |
|
281 |
+ 'agency_id': userSearch['agency_id'], |
|
282 |
+ 'authority': tabActiveByRoleType, |
|
283 |
+ }}); |
|
284 |
+ } |
|
285 |
+ |
|
286 |
+ |
|
287 |
+ //Mounted |
|
288 |
+ React.useEffect(() => { |
|
289 |
+ orgSelectListOfHierarchy(); |
|
290 |
+ seniorSelectList(); |
|
291 |
+ agentSelectList(); |
|
292 |
+ if (state.loginUser['authority'] == 'ROLE_ADMIN' || state.loginUser['authority'] == 'ROLE_GOVERNMENT') { |
|
293 |
+ governmentSelectList(); |
|
294 |
+ } |
|
295 |
+ if (state.loginUser['authority'] == 'ROLE_ADMIN') { |
|
296 |
+ adminSelectList(); |
|
297 |
+ } |
|
298 |
+ }, []); |
|
299 |
+ |
|
235 | 300 |
|
236 | 301 |
return ( |
237 | 302 |
<main> |
238 |
- <Modal_Guardian open={modalOpen} close={closeModal} header="'김복남'님의 가족"> |
|
239 |
- <div className="board-wrap"> |
|
240 |
- <SubTitle explanation={"최초 로그인 ID는 연락처, PW는 생년월일 8자리입니다."} className="margin-bottom" /> |
|
241 |
- <table className="margin-bottom2 senior-insert"> |
|
242 |
- <tr> |
|
243 |
- <th>이름</th> |
|
244 |
- <td> |
|
245 |
- <input type="text" /> |
|
246 |
- </td> |
|
247 |
- <th>생년월일</th> |
|
248 |
- <td> |
|
249 |
- <div className="flex"> |
|
250 |
- <select name="year" id="year"> |
|
251 |
- <option value="">년</option> |
|
252 |
- </select> |
|
253 |
- <select name="month" id="month"> |
|
254 |
- <option value="">월</option> |
|
255 |
- </select> |
|
256 |
- <select name="days" id="days"> |
|
257 |
- <option value="">일</option> |
|
258 |
- </select> |
|
259 |
- </div> |
|
260 |
- </td> |
|
261 |
- </tr> |
|
262 |
- <tr> |
|
263 |
- <th>연락처</th> |
|
264 |
- <td colSpan={3}> |
|
265 |
- <input type="input" maxLength="11" /> |
|
266 |
- </td> |
|
267 |
- </tr> |
|
268 |
- <tr> |
|
269 |
- <th>대상자와의 관계</th> |
|
270 |
- <td colSpan={3}> |
|
271 |
- <input type="text" /> |
|
272 |
- </td> |
|
273 |
- </tr> |
|
274 |
- </table> |
|
275 |
- <div className="btn-wrap flex-center margin-bottom5"> |
|
276 |
- <Button |
|
277 |
- className={"btn-small red-btn"} |
|
278 |
- btnName={"추가"} |
|
279 |
- onClick={() => { |
|
280 |
- navigate("/SeniorInsert"); |
|
281 |
- }} |
|
282 |
- /> |
|
283 |
- </div> |
|
284 |
- <div> |
|
285 |
- <Table |
|
286 |
- className={"caregiver-user"} |
|
287 |
- head={thead3} |
|
288 |
- contents={content3} |
|
289 |
- contentKey={key3} |
|
290 |
- /> |
|
291 |
- </div> |
|
292 |
- </div> |
|
293 |
- </Modal_Guardian> |
|
294 |
- <Modal_SeniorInsert open={modalOpen2} close={closeModal2} header="대상자(사용자) 등록" > |
|
295 |
- </Modal_SeniorInsert> |
|
303 |
+ <Modal_Guardian open={modalGuardianIsOpen} close={modalGuardianClose}/> |
|
304 |
+ <Modal_SeniorInsert |
|
305 |
+ open={modalSeniorInsertIsOpen} |
|
306 |
+ close={modalSeniorInsertClose} |
|
307 |
+ seniorInsertCallback={() => {seniorSelectList(); modalSeniorInsertClose();}} |
|
308 |
+ defaultAgencyId={userSearch['agency_id']} |
|
309 |
+ defaultGovernmentId={userSearch['government_id']} |
|
310 |
+ /> |
|
311 |
+ |
|
296 | 312 |
<ContentTitle explanation={"사용자 관리"} /> |
297 | 313 |
<div className="content-wrap"> |
298 |
- |
|
299 |
- <div |
|
300 |
- className="flex-align-start userauthoriylist" |
|
301 |
- style={{ height: "calc(100% - 61px)" }} |
|
302 |
- > |
|
314 |
+ <div className="flex-align-start userauthoriylist" style={{ height: "calc(100% - 61px)" }}> |
|
303 | 315 |
<div className="left" style={{ height: "100%", }}> |
304 | 316 |
<div style={{ height: "100%" }}> |
305 | 317 |
<SubTitle |
306 |
- explanation={"관리기관 리스트"} |
|
318 |
+ explanation={"기관 리스트"} |
|
307 | 319 |
className="margin-bottom" |
308 | 320 |
/> |
309 |
- <Category /> |
|
321 |
+ {/* 카테고리 디자인 필요 (a.active 클래스 필요) */} |
|
322 |
+ <div style={{width: '100%', fontSize: '16px'}}> |
|
323 |
+ {/* <a className={() => {return "active"}} onClick={adminChange}>올잇메디</a> */} |
|
324 |
+ <a onClick={adminChange} |
|
325 |
+ className={userSearch['government_id'] == null && userSearch['agency_id'] == null ? "active" : ""}> |
|
326 |
+ 올잇메디 |
|
327 |
+ </a> |
|
328 |
+ <ul style={{marginLeft: '15px'}}> |
|
329 |
+ {orgListOfHierarchy.map((item, idx) => { return ( |
|
330 |
+ <li style={{margin: '10px 0px'}} key={idx}> |
|
331 |
+ <span style={{marginRight: '5px'}}>└</span> |
|
332 |
+ <a onClick={() => {governmentChange(item['government_id'])}} |
|
333 |
+ className={item['government_id'] == userSearch['government_id'] ? "active" : ""}> |
|
334 |
+ {item['government_name']} |
|
335 |
+ </a> |
|
336 |
+ {item['agencyList'] != undefined && item['agencyList'] != null ? |
|
337 |
+ <ul style={{marginLeft: '15px'}}> |
|
338 |
+ {item['agencyList'].map((item2, idx2) => { return ( |
|
339 |
+ <li style={{margin: '10px 0px'}} key={idx2}> |
|
340 |
+ <span style={{marginRight: '5px'}}>└</span> |
|
341 |
+ <a onClick={() => {agencyChange(item['government_id'], item2['agency_id'])}} |
|
342 |
+ className={item2['agency_id'] == userSearch['agency_id'] ? "active" : ""}> |
|
343 |
+ {item2['agency_name']} |
|
344 |
+ </a> |
|
345 |
+ </li> |
|
346 |
+ )})} |
|
347 |
+ </ul> |
|
348 |
+ : null |
|
349 |
+ } |
|
350 |
+ </li> |
|
351 |
+ )})} |
|
352 |
+ </ul> |
|
353 |
+ </div> |
|
354 |
+ {/* 카테고리 디자인 필요 */} |
|
310 | 355 |
</div> |
311 | 356 |
</div> |
312 | 357 |
<div className="right" style={{ height: "100%", }}> |
313 | 358 |
<div style={{ height: "100%" }}> |
314 |
- <SubTitle |
|
315 |
- explanation={`${agencyName} 사용자 리스트`} |
|
316 |
- className="margin-bottom" |
|
317 |
- /> |
|
359 |
+ <SubTitle explanation={`사용자 리스트`} className="margin-bottom"/> |
|
318 | 360 |
<div className="tab-container"> |
319 |
- <ul className="tab-menu flex-end"> |
|
320 |
- {data.map((item) => ( |
|
321 |
- <li |
|
322 |
- key={item.id} |
|
323 |
- className={index === item.id ? "active" : null} |
|
324 |
- onClick={() => setIndex(item.id)} |
|
325 |
- > |
|
326 |
- {item.title} |
|
327 |
- </li> |
|
328 |
- ))} |
|
361 |
+ |
|
362 |
+ {/* 탭 제목 */} |
|
363 |
+ <ul className="tab-menu flex-end" > |
|
364 |
+ <li onClick={() => setTabActiveByRoleType('ROLE_SENIOR')} className={tabActiveByRoleType == 'ROLE_SENIOR' ? "active" : null}>대상자(어르신) ({senior.userListCount})</li> |
|
365 |
+ <li onClick={() => setTabActiveByRoleType('ROLE_AGENCY')} className={tabActiveByRoleType == 'ROLE_AGENCY' ? "active" : null}>담당자 ({agent.userListCount})</li> |
|
366 |
+ <li onClick={() => setTabActiveByRoleType('ROLE_GOVERNMENT')} className={tabActiveByRoleType == 'ROLE_GOVERNMENT' ? "active" : null}>기관 관리자 ({government.userListCount})</li> |
|
367 |
+ <li onClick={() => setTabActiveByRoleType('ROLE_ADMIN')} className={tabActiveByRoleType == 'ROLE_ADMIN' ? "active" : null}>시스템 관리자 ({admin.userListCount})</li> |
|
329 | 368 |
</ul> |
369 |
+ |
|
370 |
+ {/* 탭 내용 */} |
|
330 | 371 |
<div className="content-wrap userlist"> |
331 |
- <ul className="tab-content"> |
|
332 |
- {data |
|
333 |
- .filter((item) => index === item.id) |
|
334 |
- .map((item) => ( |
|
335 |
- <li>{item.description}</li> |
|
336 |
- ))} |
|
337 |
- </ul> |
|
372 |
+ {{ |
|
373 |
+ /* 대상자(시니어) (시작) */ |
|
374 |
+ ROLE_SENIOR: ( |
|
375 |
+ <ul className="tab-content"> |
|
376 |
+ <div> |
|
377 |
+ |
|
378 |
+ <div className="search-management flex-start margin-bottom2"> |
|
379 |
+ <select id="searchType1" style={{maxWidth: 'fit-content'}} onChange={(e) => {seniorSearchChange("searchType", e.target.value)}}> |
|
380 |
+ <option value="" selected={senior.search.searchText == ""}>전체</option> |
|
381 |
+ <option value="user_name" selected={senior.search.searchText == "user_name"}>이름</option> |
|
382 |
+ <option value="user_phonenumber" selected={senior.search.searchText == "user_phonenumber"}>연락처</option> |
|
383 |
+ <option value="user_id" selected={senior.search.searchText == "user_id"}>아이디</option> |
|
384 |
+ </select> |
|
385 |
+ <input type="text" id="searchText1" |
|
386 |
+ value={senior.search.searchText} |
|
387 |
+ onChange={(e) => {seniorSearchChange("searchText", e.target.value)}} |
|
388 |
+ onKeyUp={(e) => {seniorSelectListEnter(e.key)}} |
|
389 |
+ /> |
|
390 |
+ <button className={"btn-small gray-btn"} onClick={() => {seniorSelectList()}}>검색</button> |
|
391 |
+ </div> |
|
392 |
+ |
|
393 |
+ <div className="btn-wrap flex-end margin-bottom"> |
|
394 |
+ <button className={"btn-small gray-btn"} onClick={() => modalSeniorInsertOpen()}>등록</button> |
|
395 |
+ </div> |
|
396 |
+ |
|
397 |
+ <table className={"protector-user"}> |
|
398 |
+ <thead> |
|
399 |
+ <tr> |
|
400 |
+ <th>No</th> |
|
401 |
+ <th>소속기관명</th> |
|
402 |
+ <th>이름</th> |
|
403 |
+ <th>생년월일</th> |
|
404 |
+ <th>성별</th> |
|
405 |
+ <th>연락처</th> |
|
406 |
+ <th>주소</th> |
|
407 |
+ |
|
408 |
+ </tr> |
|
409 |
+ </thead> |
|
410 |
+ <tbody> |
|
411 |
+ {senior.userList.map((item, idx) => { return ( |
|
412 |
+ <tr key={idx} onClick={() => {navigate("/SeniorSelectOne")}}> |
|
413 |
+ <td>{senior.userListCount - idx - (senior.search.currentPage - 1) * senior.search.perPage}</td> |
|
414 |
+ <td>{item['agency_name']}</td> |
|
415 |
+ <td>{item['user_name']}</td> |
|
416 |
+ <td>{item['user_birth']}</td> |
|
417 |
+ <td>{item['user_gender']}</td> |
|
418 |
+ <td>{item['user_phonenumber']}</td> |
|
419 |
+ <td>{item['user_address']}</td> |
|
420 |
+ </tr> |
|
421 |
+ )})} |
|
422 |
+ {senior.userList == null || senior.userList.length == 0 ? |
|
423 |
+ <tr> |
|
424 |
+ <td colSpan={7}>조회된 데이터가 없습니다</td> |
|
425 |
+ </tr> |
|
426 |
+ : null} |
|
427 |
+ </tbody> |
|
428 |
+ </table> |
|
429 |
+ <Pagination |
|
430 |
+ currentPage={senior.search.currentPage} |
|
431 |
+ perPage={senior.search.perPage} |
|
432 |
+ totalCount={senior.userListCount} |
|
433 |
+ maxRange={5} |
|
434 |
+ click={seniorSelectList} |
|
435 |
+ /> |
|
436 |
+ </div> |
|
437 |
+ </ul> |
|
438 |
+ ), |
|
439 |
+ /* 대상자(시니어) (종료) */ |
|
440 |
+ |
|
441 |
+ /* 시행기관(복지사, 간호사) 사용자 (시작) */ |
|
442 |
+ ROLE_AGENCY: ( |
|
443 |
+ <ul className="tab-content"> |
|
444 |
+ <div> |
|
445 |
+ |
|
446 |
+ <div className="search-management flex-start margin-bottom2"> |
|
447 |
+ <select id="searchType2" style={{maxWidth: 'fit-content'}} onChange={(e) => {agentSearchChange("searchType", e.target.value)}}> |
|
448 |
+ <option value="" selected={agent.search.searchText == ""}>전체</option> |
|
449 |
+ <option value="user_name" selected={agent.search.searchText == "user_name"}>이름</option> |
|
450 |
+ <option value="user_phonenumber" selected={agent.search.searchText == "user_phonenumber"}>연락처</option> |
|
451 |
+ <option value="user_id" selected={agent.search.searchText == "user_id"}>아이디</option> |
|
452 |
+ </select> |
|
453 |
+ <input id="searchText2" type="text" |
|
454 |
+ value={agent.search.searchText} |
|
455 |
+ onChange={(e) => {agentSearchChange("searchText", e.target.value)}} |
|
456 |
+ onKeyUp={(e) => {agentSelectListEnter(e.key)}} |
|
457 |
+ /> |
|
458 |
+ <button className={"btn-small gray-btn"} onClick={() => {agentSelectList()}}>검색</button> |
|
459 |
+ </div> |
|
460 |
+ |
|
461 |
+ <div className="btn-wrap flex-end margin-bottom"> |
|
462 |
+ <button className={"btn-small gray-btn"} onClick={join}>등록</button> |
|
463 |
+ </div> |
|
464 |
+ |
|
465 |
+ <table className={"senior-user"}> |
|
466 |
+ <thead> |
|
467 |
+ <tr> |
|
468 |
+ <th>No</th> |
|
469 |
+ <th>관리기관명</th> |
|
470 |
+ <th>소속기관명</th> |
|
471 |
+ <th>이름</th> |
|
472 |
+ <th>연락처</th> |
|
473 |
+ <th>이메일</th> |
|
474 |
+ <th>담당 대상자(어르신)</th> |
|
475 |
+ <th>가입승인</th> |
|
476 |
+ </tr> |
|
477 |
+ </thead> |
|
478 |
+ <tbody> |
|
479 |
+ {agent.userList.map((item, idx) => { return ( |
|
480 |
+ <tr key={idx}> |
|
481 |
+ <td>{agent.userListCount - idx - (agent.search.currentPage - 1) * agent.search.perPage}</td> |
|
482 |
+ <td>{item['government_name']}</td> |
|
483 |
+ <td>{item['agency_name']}</td> |
|
484 |
+ <td>{item['user_name']}</td> |
|
485 |
+ <td>{item['user_phonenumber']}</td> |
|
486 |
+ <td>{item['user_email']}</td> |
|
487 |
+ <td> |
|
488 |
+ <button className={"btn-small lightgray-btn"} onClick={() => modalGuardianOpen()}>담당 대상자(어르신) 보기</button> |
|
489 |
+ </td> |
|
490 |
+ <td> |
|
491 |
+ {item['is_accept'] ? "승인완료" : |
|
492 |
+ <button className={"btn-small red-btn"} onClick={() => {}}>가입승인</button> |
|
493 |
+ } |
|
494 |
+ </td> |
|
495 |
+ </tr> |
|
496 |
+ )})} |
|
497 |
+ {agent.userList == null || agent.userList.length == 0 ? |
|
498 |
+ <tr> |
|
499 |
+ <td colSpan={8}>조회된 데이터가 없습니다</td> |
|
500 |
+ </tr> |
|
501 |
+ : null} |
|
502 |
+ </tbody> |
|
503 |
+ </table> |
|
504 |
+ <Pagination |
|
505 |
+ currentPage={agent.search.currentPage} |
|
506 |
+ perPage={agent.search.perPage} |
|
507 |
+ totalCount={agent.userListCount} |
|
508 |
+ maxRange={5} |
|
509 |
+ click={agentSelectList} |
|
510 |
+ /> |
|
511 |
+ </div> |
|
512 |
+ </ul> |
|
513 |
+ ), |
|
514 |
+ /* 시행기관(복지사, 간호사) 사용자 (종료) */ |
|
515 |
+ |
|
516 |
+ /* 관리기관(지자체, 병원) 사용자 (시작) */ |
|
517 |
+ ROLE_GOVERNMENT: ( |
|
518 |
+ <ul className="tab-content"> |
|
519 |
+ <div> |
|
520 |
+ |
|
521 |
+ <div className="search-management flex-start margin-bottom2"> |
|
522 |
+ <select style={{maxWidth: 'fit-content'}} onChange={(e) => {governmentSearchChange("searchType", e.target.value)}}> |
|
523 |
+ <option value="" selected={government.search.searchText == ""}>전체</option> |
|
524 |
+ <option value="user_name" selected={government.search.searchText == "user_name"}>이름</option> |
|
525 |
+ <option value="user_phonenumber" selected={government.search.searchText == "user_phonenumber"}>연락처</option> |
|
526 |
+ <option value="user_id" selected={government.search.searchText == "user_id"}>아이디</option> |
|
527 |
+ </select> |
|
528 |
+ <input type="text" |
|
529 |
+ value={government.search.searchText} |
|
530 |
+ onChange={(e) => {governmentSearchChange("searchText", e.target.value)}} |
|
531 |
+ onKeyUp={(e) => {governmentSelectListEnter(e.key)}} |
|
532 |
+ /> |
|
533 |
+ <button className={"btn-small gray-btn"} onClick={() => {governmentSelectList()}}>검색</button> |
|
534 |
+ </div> |
|
535 |
+ |
|
536 |
+ <div className="btn-wrap flex-end margin-bottom"> |
|
537 |
+ <button className={"btn-small gray-btn"} onClick={join}>등록</button> |
|
538 |
+ </div> |
|
539 |
+ |
|
540 |
+ <table className={"senior-user"}> |
|
541 |
+ <thead> |
|
542 |
+ <tr> |
|
543 |
+ <th>No</th> |
|
544 |
+ <th>소속기관명</th> |
|
545 |
+ <th>이름</th> |
|
546 |
+ <th>연락처</th> |
|
547 |
+ <th>이메일</th> |
|
548 |
+ <th>가입승인</th> |
|
549 |
+ </tr> |
|
550 |
+ </thead> |
|
551 |
+ <tbody> |
|
552 |
+ {government.userList.map((item, idx) => { return ( |
|
553 |
+ <tr key={idx}> |
|
554 |
+ <td>{government.userListCount - idx - (government.search.currentPage - 1) * government.search.perPage}</td> |
|
555 |
+ <td>{item['government_name']}</td> |
|
556 |
+ <td>{item['user_name']}</td> |
|
557 |
+ <td>{item['user_phonenumber']}</td> |
|
558 |
+ <td>{item['user_email']}</td> |
|
559 |
+ <td> |
|
560 |
+ {item['is_accept'] ? "승인완료" : |
|
561 |
+ <button className={"btn-small red-btn"} onClick={() => {}}>가입승인</button> |
|
562 |
+ } |
|
563 |
+ </td> |
|
564 |
+ </tr> |
|
565 |
+ )})} |
|
566 |
+ {government.userList == null || government.userList.length == 0 ? |
|
567 |
+ <tr> |
|
568 |
+ <td colSpan={6}>조회된 데이터가 없습니다</td> |
|
569 |
+ </tr> |
|
570 |
+ : null} |
|
571 |
+ </tbody> |
|
572 |
+ </table> |
|
573 |
+ |
|
574 |
+ </div> |
|
575 |
+ </ul> |
|
576 |
+ ), |
|
577 |
+ /* 관리기관(지자체, 병원) 사용자 (종료) */ |
|
578 |
+ |
|
579 |
+ /* 시스템 관리자 (시작) */ |
|
580 |
+ ROLE_ADMIN: ( |
|
581 |
+ <ul className="tab-content"> |
|
582 |
+ <div> |
|
583 |
+ |
|
584 |
+ <div className="search-management flex-start margin-bottom2"> |
|
585 |
+ <select style={{maxWidth: 'fit-content'}} onChange={(e) => {adminSearchChange("searchType", e.target.value)}}> |
|
586 |
+ <option value="" selected={admin.search.searchText == ""}>전체</option> |
|
587 |
+ <option value="user_name" selected={admin.search.searchText == "user_name"}>이름</option> |
|
588 |
+ <option value="user_phonenumber" selected={admin.search.searchText == "user_phonenumber"}>연락처</option> |
|
589 |
+ <option value="user_id" selected={admin.search.searchText == "user_id"}>아이디</option> |
|
590 |
+ </select> |
|
591 |
+ <input type="text" |
|
592 |
+ value={admin.search.searchText} |
|
593 |
+ onChange={(e) => {adminSearchChange("searchText", e.target.value)}} |
|
594 |
+ onKeyUp={(e) => {adminSelectListEnter(e.key)}} |
|
595 |
+ /> |
|
596 |
+ <button className={"btn-small gray-btn"} onClick={() => {adminSelectList()}}>검색</button> |
|
597 |
+ </div> |
|
598 |
+ |
|
599 |
+ <div className="btn-wrap flex-end margin-bottom"> |
|
600 |
+ <button className={"btn-small gray-btn"} onClick={join}>등록</button> |
|
601 |
+ </div> |
|
602 |
+ |
|
603 |
+ <table className={"senior-user"}> |
|
604 |
+ <thead> |
|
605 |
+ <tr> |
|
606 |
+ <th>No</th> |
|
607 |
+ <th>이름</th> |
|
608 |
+ <th>연락처</th> |
|
609 |
+ <th>이메일</th> |
|
610 |
+ <th>가입승인</th> |
|
611 |
+ </tr> |
|
612 |
+ </thead> |
|
613 |
+ <tbody> |
|
614 |
+ {admin.userList.map((item, idx) => { return ( |
|
615 |
+ <tr key={idx}> |
|
616 |
+ <td>{admin.userListCount - idx - (admin.search.currentPage - 1) * admin.search.perPage}</td> |
|
617 |
+ <td>{item['user_name']}</td> |
|
618 |
+ <td>{item['user_phonenumber']}</td> |
|
619 |
+ <td>{item['user_email']}</td> |
|
620 |
+ <td> |
|
621 |
+ {item['is_accept'] ? "승인완료" : |
|
622 |
+ <button className={"btn-small red-btn"} onClick={() => {}}>가입승인</button> |
|
623 |
+ } |
|
624 |
+ </td> |
|
625 |
+ </tr> |
|
626 |
+ )})} |
|
627 |
+ {admin.userList == null || admin.userList.length == 0 ? |
|
628 |
+ <tr> |
|
629 |
+ <td colSpan={5}>조회된 데이터가 없습니다</td> |
|
630 |
+ </tr> |
|
631 |
+ : null} |
|
632 |
+ </tbody> |
|
633 |
+ </table> |
|
634 |
+ |
|
635 |
+ </div> |
|
636 |
+ </ul> |
|
637 |
+ ) |
|
638 |
+ /* 시스템 관리자 (종료) */ |
|
639 |
+ }[tabActiveByRoleType]} |
|
338 | 640 |
</div> |
641 |
+ |
|
339 | 642 |
</div> |
340 | 643 |
</div> |
341 | 644 |
</div> |
--- node_modules/.package-lock.json
+++ node_modules/.package-lock.json
... | ... | @@ -1050,6 +1050,29 @@ |
1050 | 1050 |
"url": "https://opencollective.com/popperjs" |
1051 | 1051 |
} |
1052 | 1052 |
}, |
1053 |
+ "node_modules/@reduxjs/toolkit": { |
|
1054 |
+ "version": "1.9.3", |
|
1055 |
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", |
|
1056 |
+ "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==", |
|
1057 |
+ "dependencies": { |
|
1058 |
+ "immer": "^9.0.16", |
|
1059 |
+ "redux": "^4.2.0", |
|
1060 |
+ "redux-thunk": "^2.4.2", |
|
1061 |
+ "reselect": "^4.1.7" |
|
1062 |
+ }, |
|
1063 |
+ "peerDependencies": { |
|
1064 |
+ "react": "^16.9.0 || ^17.0.0 || ^18", |
|
1065 |
+ "react-redux": "^7.2.1 || ^8.0.2" |
|
1066 |
+ }, |
|
1067 |
+ "peerDependenciesMeta": { |
|
1068 |
+ "react": { |
|
1069 |
+ "optional": true |
|
1070 |
+ }, |
|
1071 |
+ "react-redux": { |
|
1072 |
+ "optional": true |
|
1073 |
+ } |
|
1074 |
+ } |
|
1075 |
+ }, |
|
1053 | 1076 |
"node_modules/@types/d3": { |
1054 | 1077 |
"version": "7.4.0", |
1055 | 1078 |
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", |
... | ... | @@ -1321,6 +1344,15 @@ |
1321 | 1344 |
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", |
1322 | 1345 |
"integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" |
1323 | 1346 |
}, |
1347 |
+ "node_modules/@types/hoist-non-react-statics": { |
|
1348 |
+ "version": "3.3.1", |
|
1349 |
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", |
|
1350 |
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", |
|
1351 |
+ "dependencies": { |
|
1352 |
+ "@types/react": "*", |
|
1353 |
+ "hoist-non-react-statics": "^3.3.0" |
|
1354 |
+ } |
|
1355 |
+ }, |
|
1324 | 1356 |
"node_modules/@types/json-schema": { |
1325 | 1357 |
"version": "7.0.11", |
1326 | 1358 |
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", |
... | ... | @@ -1381,6 +1413,11 @@ |
1381 | 1413 |
"version": "3.2.0", |
1382 | 1414 |
"resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", |
1383 | 1415 |
"integrity": "sha512-3h04sJhF2rjOq8zUhyomORyKdr0RUts7FAz/JajBKGpTF0JSXjaj9fjWtAqj+pU1fwsGsHzcm3Neew3t/McUXA==" |
1416 |
+ }, |
|
1417 |
+ "node_modules/@types/use-sync-external-store": { |
|
1418 |
+ "version": "0.0.3", |
|
1419 |
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", |
|
1420 |
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" |
|
1384 | 1421 |
}, |
1385 | 1422 |
"node_modules/@webassemblyjs/ast": { |
1386 | 1423 |
"version": "1.11.1", |
... | ... | @@ -4727,6 +4764,15 @@ |
4727 | 4764 |
"postcss": "^8.1.0" |
4728 | 4765 |
} |
4729 | 4766 |
}, |
4767 |
+ "node_modules/immer": { |
|
4768 |
+ "version": "9.0.21", |
|
4769 |
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", |
|
4770 |
+ "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", |
|
4771 |
+ "funding": { |
|
4772 |
+ "type": "opencollective", |
|
4773 |
+ "url": "https://opencollective.com/immer" |
|
4774 |
+ } |
|
4775 |
+ }, |
|
4730 | 4776 |
"node_modules/import-fresh": { |
4731 | 4777 |
"version": "3.3.0", |
4732 | 4778 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", |
... | ... | @@ -6462,6 +6508,44 @@ |
6462 | 6508 |
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", |
6463 | 6509 |
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" |
6464 | 6510 |
}, |
6511 |
+ "node_modules/react-redux": { |
|
6512 |
+ "version": "8.0.5", |
|
6513 |
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", |
|
6514 |
+ "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", |
|
6515 |
+ "dependencies": { |
|
6516 |
+ "@babel/runtime": "^7.12.1", |
|
6517 |
+ "@types/hoist-non-react-statics": "^3.3.1", |
|
6518 |
+ "@types/use-sync-external-store": "^0.0.3", |
|
6519 |
+ "hoist-non-react-statics": "^3.3.2", |
|
6520 |
+ "react-is": "^18.0.0", |
|
6521 |
+ "use-sync-external-store": "^1.0.0" |
|
6522 |
+ }, |
|
6523 |
+ "peerDependencies": { |
|
6524 |
+ "@types/react": "^16.8 || ^17.0 || ^18.0", |
|
6525 |
+ "@types/react-dom": "^16.8 || ^17.0 || ^18.0", |
|
6526 |
+ "react": "^16.8 || ^17.0 || ^18.0", |
|
6527 |
+ "react-dom": "^16.8 || ^17.0 || ^18.0", |
|
6528 |
+ "react-native": ">=0.59", |
|
6529 |
+ "redux": "^4" |
|
6530 |
+ }, |
|
6531 |
+ "peerDependenciesMeta": { |
|
6532 |
+ "@types/react": { |
|
6533 |
+ "optional": true |
|
6534 |
+ }, |
|
6535 |
+ "@types/react-dom": { |
|
6536 |
+ "optional": true |
|
6537 |
+ }, |
|
6538 |
+ "react-dom": { |
|
6539 |
+ "optional": true |
|
6540 |
+ }, |
|
6541 |
+ "react-native": { |
|
6542 |
+ "optional": true |
|
6543 |
+ }, |
|
6544 |
+ "redux": { |
|
6545 |
+ "optional": true |
|
6546 |
+ } |
|
6547 |
+ } |
|
6548 |
+ }, |
|
6465 | 6549 |
"node_modules/react-resize-detector": { |
6466 | 6550 |
"version": "7.1.2", |
6467 | 6551 |
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz", |
... | ... | @@ -6643,6 +6727,22 @@ |
6643 | 6727 |
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", |
6644 | 6728 |
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" |
6645 | 6729 |
}, |
6730 |
+ "node_modules/redux": { |
|
6731 |
+ "version": "4.2.1", |
|
6732 |
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", |
|
6733 |
+ "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", |
|
6734 |
+ "dependencies": { |
|
6735 |
+ "@babel/runtime": "^7.9.2" |
|
6736 |
+ } |
|
6737 |
+ }, |
|
6738 |
+ "node_modules/redux-thunk": { |
|
6739 |
+ "version": "2.4.2", |
|
6740 |
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", |
|
6741 |
+ "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", |
|
6742 |
+ "peerDependencies": { |
|
6743 |
+ "redux": "^4" |
|
6744 |
+ } |
|
6745 |
+ }, |
|
6646 | 6746 |
"node_modules/regenerator-runtime": { |
6647 | 6747 |
"version": "0.13.11", |
6648 | 6748 |
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", |
... | ... | @@ -6712,6 +6812,11 @@ |
6712 | 6812 |
"engines": { |
6713 | 6813 |
"node": ">=0.10" |
6714 | 6814 |
} |
6815 |
+ }, |
|
6816 |
+ "node_modules/reselect": { |
|
6817 |
+ "version": "4.1.7", |
|
6818 |
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", |
|
6819 |
+ "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" |
|
6715 | 6820 |
}, |
6716 | 6821 |
"node_modules/resolve": { |
6717 | 6822 |
"version": "1.22.1", |
... | ... | @@ -8057,6 +8162,14 @@ |
8057 | 8162 |
"node": ">=0.10.0" |
8058 | 8163 |
} |
8059 | 8164 |
}, |
8165 |
+ "node_modules/use-sync-external-store": { |
|
8166 |
+ "version": "1.2.0", |
|
8167 |
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", |
|
8168 |
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", |
|
8169 |
+ "peerDependencies": { |
|
8170 |
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" |
|
8171 |
+ } |
|
8172 |
+ }, |
|
8060 | 8173 |
"node_modules/util-deprecate": { |
8061 | 8174 |
"version": "1.0.2", |
8062 | 8175 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", |
--- package-lock.json
+++ package-lock.json
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 |
"@emotion/styled": "^11.10.5", |
17 | 17 |
"@mui/icons-material": "^5.11.0", |
18 | 18 |
"@mui/material": "^5.11.8", |
19 |
+ "@reduxjs/toolkit": "^1.9.3", |
|
19 | 20 |
"add": "^2.0.6", |
20 | 21 |
"babel-loader": "^8.2.5", |
21 | 22 |
"chart.js": "^4.2.0", |
... | ... | @@ -27,7 +28,6 @@ |
27 | 28 |
"file-loader": "^6.2.0", |
28 | 29 |
"fs": "0.0.1-security", |
29 | 30 |
"g3": "^0.2.37", |
30 |
- "history": "5.3.0", |
|
31 | 31 |
"moment": "^2.29.4", |
32 | 32 |
"mysql": "2.18.1", |
33 | 33 |
"oracledb": "5.5.0", |
... | ... | @@ -38,6 +38,7 @@ |
38 | 38 |
"react-dom": "18.2.0", |
39 | 39 |
"react-is": "18.2.0", |
40 | 40 |
"react-kakao-maps-sdk": "^1.1.5", |
41 |
+ "react-redux": "^8.0.5", |
|
41 | 42 |
"react-router": "6.3.0", |
42 | 43 |
"react-router-dom": "6.3.0", |
43 | 44 |
"recharts": "^2.1.16", |
... | ... | @@ -1099,6 +1100,29 @@ |
1099 | 1100 |
"url": "https://opencollective.com/popperjs" |
1100 | 1101 |
} |
1101 | 1102 |
}, |
1103 |
+ "node_modules/@reduxjs/toolkit": { |
|
1104 |
+ "version": "1.9.3", |
|
1105 |
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", |
|
1106 |
+ "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==", |
|
1107 |
+ "dependencies": { |
|
1108 |
+ "immer": "^9.0.16", |
|
1109 |
+ "redux": "^4.2.0", |
|
1110 |
+ "redux-thunk": "^2.4.2", |
|
1111 |
+ "reselect": "^4.1.7" |
|
1112 |
+ }, |
|
1113 |
+ "peerDependencies": { |
|
1114 |
+ "react": "^16.9.0 || ^17.0.0 || ^18", |
|
1115 |
+ "react-redux": "^7.2.1 || ^8.0.2" |
|
1116 |
+ }, |
|
1117 |
+ "peerDependenciesMeta": { |
|
1118 |
+ "react": { |
|
1119 |
+ "optional": true |
|
1120 |
+ }, |
|
1121 |
+ "react-redux": { |
|
1122 |
+ "optional": true |
|
1123 |
+ } |
|
1124 |
+ } |
|
1125 |
+ }, |
|
1102 | 1126 |
"node_modules/@types/d3": { |
1103 | 1127 |
"version": "7.4.0", |
1104 | 1128 |
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", |
... | ... | @@ -1370,6 +1394,15 @@ |
1370 | 1394 |
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", |
1371 | 1395 |
"integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" |
1372 | 1396 |
}, |
1397 |
+ "node_modules/@types/hoist-non-react-statics": { |
|
1398 |
+ "version": "3.3.1", |
|
1399 |
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", |
|
1400 |
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", |
|
1401 |
+ "dependencies": { |
|
1402 |
+ "@types/react": "*", |
|
1403 |
+ "hoist-non-react-statics": "^3.3.0" |
|
1404 |
+ } |
|
1405 |
+ }, |
|
1373 | 1406 |
"node_modules/@types/json-schema": { |
1374 | 1407 |
"version": "7.0.11", |
1375 | 1408 |
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", |
... | ... | @@ -1430,6 +1463,11 @@ |
1430 | 1463 |
"version": "3.2.0", |
1431 | 1464 |
"resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", |
1432 | 1465 |
"integrity": "sha512-3h04sJhF2rjOq8zUhyomORyKdr0RUts7FAz/JajBKGpTF0JSXjaj9fjWtAqj+pU1fwsGsHzcm3Neew3t/McUXA==" |
1466 |
+ }, |
|
1467 |
+ "node_modules/@types/use-sync-external-store": { |
|
1468 |
+ "version": "0.0.3", |
|
1469 |
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", |
|
1470 |
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" |
|
1433 | 1471 |
}, |
1434 | 1472 |
"node_modules/@webassemblyjs/ast": { |
1435 | 1473 |
"version": "1.11.1", |
... | ... | @@ -4822,6 +4860,15 @@ |
4822 | 4860 |
"postcss": "^8.1.0" |
4823 | 4861 |
} |
4824 | 4862 |
}, |
4863 |
+ "node_modules/immer": { |
|
4864 |
+ "version": "9.0.21", |
|
4865 |
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", |
|
4866 |
+ "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", |
|
4867 |
+ "funding": { |
|
4868 |
+ "type": "opencollective", |
|
4869 |
+ "url": "https://opencollective.com/immer" |
|
4870 |
+ } |
|
4871 |
+ }, |
|
4825 | 4872 |
"node_modules/import-fresh": { |
4826 | 4873 |
"version": "3.3.0", |
4827 | 4874 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", |
... | ... | @@ -6563,6 +6610,44 @@ |
6563 | 6610 |
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", |
6564 | 6611 |
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" |
6565 | 6612 |
}, |
6613 |
+ "node_modules/react-redux": { |
|
6614 |
+ "version": "8.0.5", |
|
6615 |
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", |
|
6616 |
+ "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", |
|
6617 |
+ "dependencies": { |
|
6618 |
+ "@babel/runtime": "^7.12.1", |
|
6619 |
+ "@types/hoist-non-react-statics": "^3.3.1", |
|
6620 |
+ "@types/use-sync-external-store": "^0.0.3", |
|
6621 |
+ "hoist-non-react-statics": "^3.3.2", |
|
6622 |
+ "react-is": "^18.0.0", |
|
6623 |
+ "use-sync-external-store": "^1.0.0" |
|
6624 |
+ }, |
|
6625 |
+ "peerDependencies": { |
|
6626 |
+ "@types/react": "^16.8 || ^17.0 || ^18.0", |
|
6627 |
+ "@types/react-dom": "^16.8 || ^17.0 || ^18.0", |
|
6628 |
+ "react": "^16.8 || ^17.0 || ^18.0", |
|
6629 |
+ "react-dom": "^16.8 || ^17.0 || ^18.0", |
|
6630 |
+ "react-native": ">=0.59", |
|
6631 |
+ "redux": "^4" |
|
6632 |
+ }, |
|
6633 |
+ "peerDependenciesMeta": { |
|
6634 |
+ "@types/react": { |
|
6635 |
+ "optional": true |
|
6636 |
+ }, |
|
6637 |
+ "@types/react-dom": { |
|
6638 |
+ "optional": true |
|
6639 |
+ }, |
|
6640 |
+ "react-dom": { |
|
6641 |
+ "optional": true |
|
6642 |
+ }, |
|
6643 |
+ "react-native": { |
|
6644 |
+ "optional": true |
|
6645 |
+ }, |
|
6646 |
+ "redux": { |
|
6647 |
+ "optional": true |
|
6648 |
+ } |
|
6649 |
+ } |
|
6650 |
+ }, |
|
6566 | 6651 |
"node_modules/react-resize-detector": { |
6567 | 6652 |
"version": "7.1.2", |
6568 | 6653 |
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz", |
... | ... | @@ -6744,6 +6829,22 @@ |
6744 | 6829 |
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", |
6745 | 6830 |
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" |
6746 | 6831 |
}, |
6832 |
+ "node_modules/redux": { |
|
6833 |
+ "version": "4.2.1", |
|
6834 |
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", |
|
6835 |
+ "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", |
|
6836 |
+ "dependencies": { |
|
6837 |
+ "@babel/runtime": "^7.9.2" |
|
6838 |
+ } |
|
6839 |
+ }, |
|
6840 |
+ "node_modules/redux-thunk": { |
|
6841 |
+ "version": "2.4.2", |
|
6842 |
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", |
|
6843 |
+ "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", |
|
6844 |
+ "peerDependencies": { |
|
6845 |
+ "redux": "^4" |
|
6846 |
+ } |
|
6847 |
+ }, |
|
6747 | 6848 |
"node_modules/regenerator-runtime": { |
6748 | 6849 |
"version": "0.13.11", |
6749 | 6850 |
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", |
... | ... | @@ -6813,6 +6914,11 @@ |
6813 | 6914 |
"engines": { |
6814 | 6915 |
"node": ">=0.10" |
6815 | 6916 |
} |
6917 |
+ }, |
|
6918 |
+ "node_modules/reselect": { |
|
6919 |
+ "version": "4.1.7", |
|
6920 |
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", |
|
6921 |
+ "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" |
|
6816 | 6922 |
}, |
6817 | 6923 |
"node_modules/resolve": { |
6818 | 6924 |
"version": "1.22.1", |
... | ... | @@ -8158,6 +8264,14 @@ |
8158 | 8264 |
"node": ">=0.10.0" |
8159 | 8265 |
} |
8160 | 8266 |
}, |
8267 |
+ "node_modules/use-sync-external-store": { |
|
8268 |
+ "version": "1.2.0", |
|
8269 |
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", |
|
8270 |
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", |
|
8271 |
+ "peerDependencies": { |
|
8272 |
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" |
|
8273 |
+ } |
|
8274 |
+ }, |
|
8161 | 8275 |
"node_modules/util-deprecate": { |
8162 | 8276 |
"version": "1.0.2", |
8163 | 8277 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", |
--- package.json
+++ package.json
... | ... | @@ -11,6 +11,7 @@ |
11 | 11 |
"@emotion/styled": "^11.10.5", |
12 | 12 |
"@mui/icons-material": "^5.11.0", |
13 | 13 |
"@mui/material": "^5.11.8", |
14 |
+ "@reduxjs/toolkit": "^1.9.3", |
|
14 | 15 |
"add": "^2.0.6", |
15 | 16 |
"babel-loader": "^8.2.5", |
16 | 17 |
"chart.js": "^4.2.0", |
... | ... | @@ -22,7 +23,6 @@ |
22 | 23 |
"file-loader": "^6.2.0", |
23 | 24 |
"fs": "0.0.1-security", |
24 | 25 |
"g3": "^0.2.37", |
25 |
- "history": "5.3.0", |
|
26 | 26 |
"moment": "^2.29.4", |
27 | 27 |
"mysql": "2.18.1", |
28 | 28 |
"oracledb": "5.5.0", |
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 |
"react-dom": "18.2.0", |
34 | 34 |
"react-is": "18.2.0", |
35 | 35 |
"react-kakao-maps-sdk": "^1.1.5", |
36 |
+ "react-redux": "^8.0.5", |
|
36 | 37 |
"react-router": "6.3.0", |
37 | 38 |
"react-router-dom": "6.3.0", |
38 | 39 |
"recharts": "^2.1.16", |
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?