
230417 최정우 1. 대상자, 보호자 등록시, 주소 API(+좌표API) 적용 2. 기관 관리자 메인화면 Leaflet 지도 적용
1. 대상자, 보호자 등록시, 주소 API(+좌표API) 적용 2. 기관 관리자 메인화면 Leaflet 지도 적용
@bcf9ef5d78c7fbeeb64505edb153eeba11e40935
--- Global.js
+++ Global.js
... | ... | @@ -5,8 +5,11 @@ |
5 | 5 |
const SERVICE_STATUS = process.env.NODE_ENV;//development, production |
6 | 6 |
const PORT = 80; |
7 | 7 |
const API_SERVER_HOST = 'localhost:8080' |
8 |
-//const JUSO_API_KEY = 'U01TX0FVVEgyMDIzMDQxNzE2MTgyNzExMzY5MzU=='//실사용 Key |
|
9 |
-const JUSO_API_KEY = 'U01TX0FVVEgyMDIyMTEyMTE3NDE1NzExMzI0MjU=';//실사용 Key 사용가능하면, 제거 |
|
8 |
+//const JUSO_API_KEY = 'U01TX0FVVEgyMDIzMDQxNzIxNDY1NjExMzY5NTg='//실사용 Key u-dolbom.com |
|
9 |
+//const JUSO_CORRD_API_KEY = 'U01TX0FVVEgyMDIzMDQxNzE2MTgyNzExMzY5MzE=';//실사용 Key u-dolbom.com |
|
10 |
+const JUSO_API_KEY = 'U01TX0FVVEgyMDIyMTEyMTE3NDE1NzExMzI0MjU=';//Test용 |
|
11 |
+const JUSO_CORRD_API_KEY = 'U01TX0FVVEgyMDIyMTEyMTE4MDIxOTExMzI0MzU=';//Test용 |
|
12 |
+ |
|
10 | 13 |
|
11 | 14 |
module.exports = { |
12 | 15 |
PROJECT_NAME, |
... | ... | @@ -16,5 +19,6 @@ |
16 | 19 |
SERVICE_STATUS, |
17 | 20 |
PORT, |
18 | 21 |
API_SERVER_HOST, |
19 |
- JUSO_API_KEY |
|
22 |
+ JUSO_API_KEY, |
|
23 |
+ JUSO_CORRD_API_KEY |
|
20 | 24 |
}(No newline at end of file) |
--- client/resources/css/main.css
+++ client/resources/css/main.css
... | ... | @@ -1327,4 +1327,35 @@ |
1327 | 1327 |
|
1328 | 1328 |
} |
1329 | 1329 |
.senior-table span{display: none;} |
1330 |
-.senior-table span img{display: none; }(No newline at end of file) |
|
1330 |
+.senior-table span img{display: none; } |
|
1331 |
+ |
|
1332 |
+ |
|
1333 |
+ul.list-box { |
|
1334 |
+ width: 100%; |
|
1335 |
+ max-height: 100px; |
|
1336 |
+ overflow: auto; |
|
1337 |
+ border: 1px solid #d3d3d3; |
|
1338 |
+ border-radius: 5px; |
|
1339 |
+} |
|
1340 |
+ul.list-box > li { |
|
1341 |
+ padding: 0.5rem 1rem; |
|
1342 |
+ text-align: left; |
|
1343 |
+ font-size: 1.3rem; |
|
1344 |
+ overflow: hidden; |
|
1345 |
+ text-overflow: ellipsis; |
|
1346 |
+ white-space: nowrap; |
|
1347 |
+} |
|
1348 |
+ul.list-box > li:hover { |
|
1349 |
+ background: #ff5c00; |
|
1350 |
+ color: #fff; |
|
1351 |
+} |
|
1352 |
+ul.list-box > li.active { |
|
1353 |
+ background: #f25430; |
|
1354 |
+ color: #fff; |
|
1355 |
+} |
|
1356 |
+ |
|
1357 |
+ |
|
1358 |
+.leaflet-background-radius-icon{ |
|
1359 |
+ background: #f25430; |
|
1360 |
+ border-radius: 50%; |
|
1361 |
+}(No newline at end of file) |
+++ client/resources/files/images/house.png
Binary file is not shown |
--- client/views/component/Modal_Guardian.jsx
+++ client/views/component/Modal_Guardian.jsx
... | ... | @@ -1,6 +1,9 @@ |
1 | 1 |
import React from "react"; |
2 | 2 |
import SubTitle from "./SubTitle.jsx"; |
3 | 3 |
import CommonUtil from "../../resources/js/CommonUtil.js"; |
4 |
+import {JUSO_API_KEY, JUSO_CORRD_API_KEY} from "../../../Global.js"; |
|
5 |
+ |
|
6 |
+import proj4 from "proj4"; |
|
4 | 7 |
|
5 | 8 |
export default function Modal_Guardian({ open, close, guardianManagementCallback, seniorId, guardianBySenior }) { |
6 | 9 |
|
... | ... | @@ -104,13 +107,18 @@ |
104 | 107 |
alert("연락처를 입력해 주세요."); |
105 | 108 |
return false; |
106 | 109 |
} |
107 |
- if (isIdCheck == false) { |
|
110 |
+ if (CommonUtil.isEmpty(guardian['guardian_id']) && isIdCheck == false) { |
|
108 | 111 |
alert("연락처 중복확인을 해주세요."); |
109 | 112 |
return false; |
110 | 113 |
} |
111 | 114 |
if (CommonUtil.isEmpty(guardian['user_address']) == true) { |
112 | 115 |
guardianRef.current['user_address'].focus(); |
113 | 116 |
alert("주소를 입력해 주세요."); |
117 |
+ return false; |
|
118 |
+ } |
|
119 |
+ if (CommonUtil.isEmpty(guardian['zip_no']) == true) { |
|
120 |
+ guardianRef.current['user_address'].focus(); |
|
121 |
+ alert("검색을 통해 주소를 선택해 주세요."); |
|
114 | 122 |
return false; |
115 | 123 |
} |
116 | 124 |
if (CommonUtil.isEmpty(guardian['senior_relationship']) == true) { |
... | ... | @@ -201,6 +209,80 @@ |
201 | 209 |
|
202 | 210 |
|
203 | 211 |
|
212 |
+ //주소 검색 결과 객체 |
|
213 |
+ const [jusoList, setJusoList] = React.useState({ |
|
214 |
+ common: { |
|
215 |
+ countPerPage: 10, |
|
216 |
+ currentPage: 1, |
|
217 |
+ errorCode: '0', |
|
218 |
+ errorMessage: '정상', |
|
219 |
+ totalCount: 0 |
|
220 |
+ }, juso: [], |
|
221 |
+ }); |
|
222 |
+ //주소 검색 |
|
223 |
+ const jusoSearch = (currentPage) => { |
|
224 |
+ if (CommonUtil.isEmpty(guardian['user_address']) == true) { |
|
225 |
+ guardianRef.current['user_address'].focus(); |
|
226 |
+ alert("주소를 입력해 주세요."); |
|
227 |
+ return false; |
|
228 |
+ } |
|
229 |
+ // console.log("check done"); |
|
230 |
+ const vm = this; |
|
231 |
+ let url = 'https://business.juso.go.kr/addrlink/addrLinkApi.do' |
|
232 |
+ url += `?currentPage=${CommonUtil.isEmpty(currentPage) ? 1 : currentPage}` |
|
233 |
+ url += '&countPerPage=10' |
|
234 |
+ url += '&resultType=json' |
|
235 |
+ url += `&keyword=${guardian['user_address']}` |
|
236 |
+ url += `&confmKey=${JUSO_API_KEY}`; |
|
237 |
+ fetch(url, { |
|
238 |
+ method: "GET", |
|
239 |
+ }).then((response) => response.json()).then((data) => { |
|
240 |
+ console.log("주소 검색 결과(건수) : ", data); |
|
241 |
+ setJusoList(data.results); |
|
242 |
+ if (data.results.common.errorCode != '0') { |
|
243 |
+ alert(data.results.common.errorMessage); |
|
244 |
+ } else { |
|
245 |
+ if (CommonUtil.isEmpty(data.results.juso)) { |
|
246 |
+ alert('조회된 주소 정보가 없습니다.'); |
|
247 |
+ } |
|
248 |
+ } |
|
249 |
+ }).catch((error) => { |
|
250 |
+ console.log('jusoSearch() : ', error); |
|
251 |
+ }); |
|
252 |
+ }; |
|
253 |
+ |
|
254 |
+ const grs80 = "+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"; |
|
255 |
+ const wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; |
|
256 |
+ //주소 정보 활용 좌표 검색 |
|
257 |
+ const coordSearch = () => { |
|
258 |
+ console.log("check guardian : ", guardian); |
|
259 |
+ let url = 'https://business.juso.go.kr/addrlink/addrCoordApi.do' |
|
260 |
+ url += `?admCd=${guardian['adm_cd']}` |
|
261 |
+ url += `&rnMgtSn=${guardian['rn_mgt_sn']}` |
|
262 |
+ url += `&udrtYn=${guardian['udrt_yn']}` |
|
263 |
+ url += `&buldMnnm=${guardian['buld_mnnm']}` |
|
264 |
+ url += `&buldSlno=${guardian['buld_slno']}` |
|
265 |
+ url += '&resultType=json' |
|
266 |
+ url += `&confmKey=${JUSO_CORRD_API_KEY}`; |
|
267 |
+ fetch(url, { |
|
268 |
+ method: "GET", |
|
269 |
+ }).then((response) => response.json()).then((data) => { |
|
270 |
+ console.log("주소 정보 활용 좌표 검색 결과(건수) : ", data); |
|
271 |
+ //setJusoList(data.results); |
|
272 |
+ if (data.results.common.errorCode == '0' && CommonUtil.isEmpty(data.results.juso) == false) { |
|
273 |
+ let grs80Point = [parseFloat(data.results.juso[0].entX), parseFloat(data.results.juso[0].entY)]; |
|
274 |
+ let wgs84Point = proj4(grs80, wgs84).forward(grs80Point); |
|
275 |
+ guardian['x'] = wgs84Point[0]; |
|
276 |
+ guardian['y'] = wgs84Point[1]; |
|
277 |
+ setGuardian({...guardian}); |
|
278 |
+ } |
|
279 |
+ }).catch((error) => { |
|
280 |
+ console.log('jusoSearch() : ', error); |
|
281 |
+ }); |
|
282 |
+ }; |
|
283 |
+ |
|
284 |
+ |
|
285 |
+ |
|
204 | 286 |
//Mounted |
205 | 287 |
React.useEffect(() => { |
206 | 288 |
console.log('guardianBySenior : ', guardianBySenior); |
... | ... | @@ -267,17 +349,24 @@ |
267 | 349 |
<tr> |
268 | 350 |
<th><span style={{color : "red"}}>*</span>연락처</th> |
269 | 351 |
<td colSpan={3}> |
270 |
- <input type="number" maxLength="11" style={{width: 'calc(100% - 160px)'}} |
|
352 |
+ {CommonUtil.isEmpty(guardian['guardian_id']) ? |
|
353 |
+ <> |
|
354 |
+ <input type="number" maxLength="11" style={{width: 'calc(100% - 160px)'}} |
|
355 |
+ value={guardian['user_phonenumber']} |
|
356 |
+ onChange={(e) => {guardianValueChange('user_phonenumber', e.target.value); setIsIdCheck(false);}} |
|
357 |
+ ref={el => guardianRef.current['user_phonenumber'] = el} |
|
358 |
+ /> |
|
359 |
+ <button className={"red-btn btn-large"} onClick={userIdCheck}> |
|
360 |
+ 중복확인 |
|
361 |
+ </button> |
|
362 |
+ </> |
|
363 |
+ : <input type="number" maxLength="11" disabled |
|
271 | 364 |
value={guardian['user_phonenumber']} |
272 |
- onChange={(e) => {guardianValueChange('user_phonenumber', e.target.value); setIsIdCheck(false);}} |
|
273 |
- ref={el => guardianRef.current['user_phonenumber'] = el} |
|
274 |
- /> |
|
275 |
- <button className={"red-btn btn-large"} onClick={userIdCheck}> |
|
276 |
- 중복확인 |
|
277 |
- </button> |
|
365 |
+ />} |
|
278 | 366 |
</td> |
279 | 367 |
</tr> |
280 |
- <tr> |
|
368 |
+ |
|
369 |
+ {/* <tr> |
|
281 | 370 |
<th><span style={{color : "red"}}>*</span>주소</th> |
282 | 371 |
<td colSpan={3}> |
283 | 372 |
<input type="text" |
... | ... | @@ -286,7 +375,48 @@ |
286 | 375 |
ref={el => guardianRef.current['user_address'] = el} |
287 | 376 |
/> |
288 | 377 |
</td> |
378 |
+ </tr> */} |
|
379 |
+ <tr> |
|
380 |
+ <th><span style={{color : "red"}}>*</span>주소</th> |
|
381 |
+ <td colSpan={3}> |
|
382 |
+ <div> |
|
383 |
+ <input type="text" style={{width: 'calc(100% - 160px)'}} |
|
384 |
+ value={guardian['user_address']} disabled={CommonUtil.isEmpty(guardian['zip_no']) == false} |
|
385 |
+ onChange={(e) => {guardianValueChange('user_address', e.target.value)}} |
|
386 |
+ onKeyUp={(e) => {e.key == 'Enter' ? jusoSearch() : null}} |
|
387 |
+ ref={el => guardianRef.current['user_address'] = el} |
|
388 |
+ /> |
|
389 |
+ {CommonUtil.isEmpty(guardian['zip_no']) |
|
390 |
+ ? <button className={"red-btn btn-large"} onClick={() => {jusoSearch()}}>주소검색</button> |
|
391 |
+ : <button className={"gray-btn btn-large"} onClick={() => {guardianValueChange('zip_no', null)}}>다시검색</button> |
|
392 |
+ } |
|
393 |
+ </div> |
|
394 |
+ {CommonUtil.isEmpty(jusoList.juso) == false && CommonUtil.isEmpty(guardian['zip_no']) ? |
|
395 |
+ <div> |
|
396 |
+ <ul className="list-box" style={{width: '100%'}}> |
|
397 |
+ {CommonUtil.isEmpty(jusoList.juso) == false ? jusoList.juso.map((item, idx) => {return ( |
|
398 |
+ <li className={guardian['zip_no'] == item['zipNo'] ? 'active' : null} onClick={() => { |
|
399 |
+ guardian['zip_no'] = item['zipNo']; guardian['adm_cd'] = item['admCd']; |
|
400 |
+ guardian['rn_mgt_sn'] = item['rnMgtSn']; guardian['bd_mgt_sn'] = item['bdMgtSn']; |
|
401 |
+ guardian['siNsi_nmm'] = item['siNm']; guardian['sgg_nm'] = item['sggNm']; |
|
402 |
+ guardian['emd_nm'] = item['emdNm']; guardian['li_nm'] = item['liNm']; |
|
403 |
+ guardian['rn'] = item['rn']; guardian['emd_no'] = item['emdNo']; |
|
404 |
+ guardian['hemd_nm'] = item['hemdNm']; guardian['road_addr'] = item['roadAddr']; |
|
405 |
+ guardian['buld_mnnm'] = item['buldMnnm']; guardian['buld_slno'] = item['buldSlno']; |
|
406 |
+ guardian['user_address'] = item['roadAddr']; guardian['udrt_yn'] = item['udrtYn']; |
|
407 |
+ setGuardian({...guardian}); coordSearch(); |
|
408 |
+ }}> |
|
409 |
+ <span style={{fontWeight: 600}}>[지번]</span> {item['jibunAddr']} |
|
410 |
+ <br/> |
|
411 |
+ <span style={{fontWeight: 600}}>[도로명]</span> {item['roadAddr']} |
|
412 |
+ </li> |
|
413 |
+ )}): null} |
|
414 |
+ </ul> |
|
415 |
+ </div> |
|
416 |
+ : null} |
|
417 |
+ </td> |
|
289 | 418 |
</tr> |
419 |
+ |
|
290 | 420 |
<tr> |
291 | 421 |
<th><span style={{color : "red"}}>*</span>대상자와의 관계</th> |
292 | 422 |
<td colSpan={3}> |
--- client/views/component/Modal_SeniorInsert.jsx
+++ client/views/component/Modal_SeniorInsert.jsx
... | ... | @@ -3,7 +3,9 @@ |
3 | 3 |
import SubTitle from "./SubTitle.jsx"; |
4 | 4 |
|
5 | 5 |
import CommonUtil from "../../resources/js/CommonUtil.js"; |
6 |
-import {JUSO_API_KEY} from "../../../Global.js"; |
|
6 |
+import {JUSO_API_KEY, JUSO_CORRD_API_KEY} from "../../../Global.js"; |
|
7 |
+ |
|
8 |
+import proj4 from "proj4"; |
|
7 | 9 |
|
8 | 10 |
export default function Modal({ open, close, seniorInsertCallback, defaultAgentId, defaultAgencyId, defaultGovernmentId }) { |
9 | 11 |
|
... | ... | @@ -81,6 +83,23 @@ |
81 | 83 |
'authority': 'ROLE_SENIOR', |
82 | 84 |
'agency_id': !defaultAgencyId ? state.loginUser['agency_id'] : defaultAgencyId, |
83 | 85 |
'government_id': !defaultGovernmentId ? state.loginUser['government_id'] : defaultGovernmentId, |
86 |
+ |
|
87 |
+ 'zip_no': null, |
|
88 |
+ 'adm_cd': null, |
|
89 |
+ 'rn_mgt_sn': null, |
|
90 |
+ 'bd_mgt_sn': null, |
|
91 |
+ 'si_nm': null, |
|
92 |
+ 'sgg_nm': null, |
|
93 |
+ 'emd_nm': null, |
|
94 |
+ 'li_nm': null, |
|
95 |
+ 'rn': null, |
|
96 |
+ 'emd_no': null, |
|
97 |
+ 'hemd_nm': null, |
|
98 |
+ 'road_addr': null, |
|
99 |
+ 'buld_mnnm': null, |
|
100 |
+ 'buld_slno': null, |
|
101 |
+ 'x': null, |
|
102 |
+ 'y': null, |
|
84 | 103 |
|
85 | 104 |
'senior_id': null, |
86 | 105 |
'care_grade': null, |
... | ... | @@ -216,6 +235,12 @@ |
216 | 235 |
return false; |
217 | 236 |
} |
218 | 237 |
|
238 |
+ if (CommonUtil.isEmpty(senior['zip_no']) == true) { |
|
239 |
+ seniorRef.current['user_address'].focus(); |
|
240 |
+ alert("검색을 통해 주소를 선택해 주세요."); |
|
241 |
+ return false; |
|
242 |
+ } |
|
243 |
+ |
|
219 | 244 |
return true; |
220 | 245 |
} |
221 | 246 |
//시니어 등록 |
... | ... | @@ -244,25 +269,77 @@ |
244 | 269 |
} |
245 | 270 |
|
246 | 271 |
|
272 |
+ //주소 검색 결과 객체 |
|
273 |
+ const [jusoList, setJusoList] = React.useState({ |
|
274 |
+ common: { |
|
275 |
+ countPerPage: 10, |
|
276 |
+ currentPage: 1, |
|
277 |
+ errorCode: '0', |
|
278 |
+ errorMessage: '정상', |
|
279 |
+ totalCount: 0 |
|
280 |
+ }, juso: [], |
|
281 |
+ }); |
|
247 | 282 |
//주소 검색 |
248 | 283 |
const jusoSearch = (currentPage) => { |
284 |
+ if (CommonUtil.isEmpty(senior['user_address']) == true) { |
|
285 |
+ seniorRef.current['user_address'].focus(); |
|
286 |
+ alert("주소를 입력해 주세요."); |
|
287 |
+ return false; |
|
288 |
+ } |
|
249 | 289 |
// console.log("check done"); |
250 | 290 |
const vm = this; |
251 |
- let url = `https://business.juso.go.kr/addrlink/addrLinkApi.do |
|
252 |
- ?currentPage=${CommonUtil.isEmpty(currentPage) ? 1 : currentPage} |
|
253 |
- &countPerPage=10 |
|
254 |
- &resultType=json |
|
255 |
- &keyword=${senior['user_address']} |
|
256 |
- &confmKey=${JUSO_API_KEY} |
|
257 |
- `; |
|
291 |
+ let url = 'https://business.juso.go.kr/addrlink/addrLinkApi.do' |
|
292 |
+ url += `?currentPage=${CommonUtil.isEmpty(currentPage) ? 1 : currentPage}` |
|
293 |
+ url += '&countPerPage=10' |
|
294 |
+ url += '&resultType=json' |
|
295 |
+ url += `&keyword=${senior['user_address']}` |
|
296 |
+ url += `&confmKey=${JUSO_API_KEY}`; |
|
258 | 297 |
fetch(url, { |
259 | 298 |
method: "GET", |
260 | 299 |
}).then((response) => response.json()).then((data) => { |
261 |
- console.log("시니어 등록 결과(건수) : ", data); |
|
300 |
+ console.log("주소 검색 결과(건수) : ", data); |
|
301 |
+ setJusoList(data.results); |
|
302 |
+ if (data.results.common.errorCode != '0') { |
|
303 |
+ alert(data.results.common.errorMessage); |
|
304 |
+ } else { |
|
305 |
+ if (CommonUtil.isEmpty(data.results.juso)) { |
|
306 |
+ alert('조회된 주소 정보가 없습니다.'); |
|
307 |
+ } |
|
308 |
+ } |
|
262 | 309 |
}).catch((error) => { |
263 | 310 |
console.log('jusoSearch() : ', error); |
264 | 311 |
}); |
265 |
-}, |
|
312 |
+ }; |
|
313 |
+ |
|
314 |
+ const grs80 = "+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"; |
|
315 |
+ const wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; |
|
316 |
+ //주소 정보 활용 좌표 검색 |
|
317 |
+ const coordSearch = () => { |
|
318 |
+ console.log("check senior : ", senior); |
|
319 |
+ let url = 'https://business.juso.go.kr/addrlink/addrCoordApi.do' |
|
320 |
+ url += `?admCd=${senior['adm_cd']}` |
|
321 |
+ url += `&rnMgtSn=${senior['rn_mgt_sn']}` |
|
322 |
+ url += `&udrtYn=${senior['udrt_yn']}` |
|
323 |
+ url += `&buldMnnm=${senior['buld_mnnm']}` |
|
324 |
+ url += `&buldSlno=${senior['buld_slno']}` |
|
325 |
+ url += '&resultType=json' |
|
326 |
+ url += `&confmKey=${JUSO_CORRD_API_KEY}`; |
|
327 |
+ fetch(url, { |
|
328 |
+ method: "GET", |
|
329 |
+ }).then((response) => response.json()).then((data) => { |
|
330 |
+ console.log("주소 정보 활용 좌표 검색 결과(건수) : ", data); |
|
331 |
+ //setJusoList(data.results); |
|
332 |
+ if (data.results.common.errorCode == '0' && CommonUtil.isEmpty(data.results.juso) == false) { |
|
333 |
+ let grs80Point = [parseFloat(data.results.juso[0].entX), parseFloat(data.results.juso[0].entY)]; |
|
334 |
+ let wgs84Point = proj4(grs80, wgs84).forward(grs80Point); |
|
335 |
+ senior['x'] = wgs84Point[0]; |
|
336 |
+ senior['y'] = wgs84Point[1]; |
|
337 |
+ setSenior({...senior}); |
|
338 |
+ } |
|
339 |
+ }).catch((error) => { |
|
340 |
+ console.log('jusoSearch() : ', error); |
|
341 |
+ }); |
|
342 |
+ }; |
|
266 | 343 |
|
267 | 344 |
|
268 | 345 |
|
... | ... | @@ -381,11 +458,41 @@ |
381 | 458 |
<tr> |
382 | 459 |
<th><span style={{color : "red"}}>*</span>주소</th> |
383 | 460 |
<td colSpan={3}> |
384 |
- <input type="text" |
|
385 |
- value={senior['user_address']} |
|
386 |
- onChange={(e) => {seniorValueChange('user_address', e.target.value)}} |
|
387 |
- ref={el => seniorRef.current['user_address'] = el} |
|
388 |
- /> |
|
461 |
+ <div> |
|
462 |
+ <input type="text" style={{width: 'calc(100% - 160px)'}} |
|
463 |
+ value={senior['user_address']} disabled={CommonUtil.isEmpty(senior['zip_no']) == false} |
|
464 |
+ onChange={(e) => {seniorValueChange('user_address', e.target.value)}} |
|
465 |
+ onKeyUp={(e) => {e.key == 'Enter' ? jusoSearch() : null}} |
|
466 |
+ ref={el => seniorRef.current['user_address'] = el} |
|
467 |
+ /> |
|
468 |
+ {CommonUtil.isEmpty(senior['zip_no']) |
|
469 |
+ ? <button className={"red-btn btn-large"} onClick={() => {jusoSearch()}}>주소검색</button> |
|
470 |
+ : <button className={"gray-btn btn-large"} onClick={() => {seniorValueChange('zip_no', null)}}>다시검색</button> |
|
471 |
+ } |
|
472 |
+ </div> |
|
473 |
+ {CommonUtil.isEmpty(jusoList.juso) == false && CommonUtil.isEmpty(senior['zip_no']) ? |
|
474 |
+ <div> |
|
475 |
+ <ul className="list-box" style={{width: '100%'}}> |
|
476 |
+ {CommonUtil.isEmpty(jusoList.juso) == false ? jusoList.juso.map((item, idx) => {return ( |
|
477 |
+ <li className={senior['zip_no'] == item['zipNo'] ? 'active' : null} onClick={() => { |
|
478 |
+ senior['zip_no'] = item['zipNo']; senior['adm_cd'] = item['admCd']; |
|
479 |
+ senior['rn_mgt_sn'] = item['rnMgtSn']; senior['bd_mgt_sn'] = item['bdMgtSn']; |
|
480 |
+ senior['siNsi_nmm'] = item['siNm']; senior['sgg_nm'] = item['sggNm']; |
|
481 |
+ senior['emd_nm'] = item['emdNm']; senior['li_nm'] = item['liNm']; |
|
482 |
+ senior['rn'] = item['rn']; senior['emd_no'] = item['emdNo']; |
|
483 |
+ senior['hemd_nm'] = item['hemdNm']; senior['road_addr'] = item['roadAddr']; |
|
484 |
+ senior['buld_mnnm'] = item['buldMnnm']; senior['buld_slno'] = item['buldSlno']; |
|
485 |
+ senior['user_address'] = item['roadAddr']; senior['udrt_yn'] = item['udrtYn']; |
|
486 |
+ setSenior({...senior}); coordSearch(); |
|
487 |
+ }}> |
|
488 |
+ <span style={{fontWeight: 600}}>[지번]</span> {item['jibunAddr']} |
|
489 |
+ <br/> |
|
490 |
+ <span style={{fontWeight: 600}}>[도로명]</span> {item['roadAddr']} |
|
491 |
+ </li> |
|
492 |
+ )}): null} |
|
493 |
+ </ul> |
|
494 |
+ </div> |
|
495 |
+ : null} |
|
389 | 496 |
</td> |
390 | 497 |
</tr> |
391 | 498 |
<tr> |
--- client/views/index.html
+++ client/views/index.html
... | ... | @@ -6,7 +6,8 @@ |
6 | 6 |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
7 | 7 |
<meta name="description" content="Node React Web"> |
8 | 8 |
<link rel="icon" href="" /> |
9 |
- <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey= 557664ec353e27affe3d6c3c513b7183"></script> |
|
9 |
+ <!-- <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey= 557664ec353e27affe3d6c3c513b7183"></script> --> |
|
10 |
+ |
|
10 | 11 |
<title>시니어 케어 시스템</title> |
11 | 12 |
</head> |
12 | 13 |
|
--- client/views/pages/healthcare/Healthcare.jsx
+++ client/views/pages/healthcare/Healthcare.jsx
... | ... | @@ -254,7 +254,7 @@ |
254 | 254 |
</select> |
255 | 255 |
<input type="text" className="senior-search" value={senior.search.searchText} |
256 | 256 |
onChange={(e) => {senior.search.searchText = e.target.value; setSenior({...senior});}} |
257 |
- onKeyUp={(e) => searchingEnter(e)}/> |
|
257 |
+ onKeyUp={(e) => searchingEnter(e.key)}/> |
|
258 | 258 |
<button className="btn-small gray-btn" onClick={searching}>검색</button> |
259 | 259 |
</div> |
260 | 260 |
|
--- client/views/pages/healthcare/Medicalcare.jsx
+++ client/views/pages/healthcare/Medicalcare.jsx
... | ... | @@ -988,7 +988,7 @@ |
988 | 988 |
</select> |
989 | 989 |
<input type="text" className="senior-search" value={senior.search.searchText} |
990 | 990 |
onChange={(e) => {senior.search.searchText = e.target.value; setSenior({...senior});}} |
991 |
- onKeyUp={(e) => searchingEnter(e)}/> |
|
991 |
+ onKeyUp={(e) => searchingEnter(e.key)}/> |
|
992 | 992 |
<button className="btn-small gray-btn" onClick={searching}>검색</button> |
993 | 993 |
</div> |
994 | 994 |
|
--- client/views/pages/main/Main_government.jsx
+++ client/views/pages/main/Main_government.jsx
... | ... | @@ -1,8 +1,14 @@ |
1 | 1 |
import React,{useState} from "react"; |
2 | 2 |
import { useSelector } from "react-redux"; |
3 | 3 |
|
4 |
+ |
|
5 |
+ |
|
6 |
+import { MapContainer, TileLayer, LayerGroup, Marker, Circle, CircleMarker, Tooltip, Popup, useMap } from 'react-leaflet'; |
|
7 |
+import L, { CRS, latLng, bounds } from 'leaflet'; |
|
8 |
+ |
|
9 |
+ |
|
4 | 10 |
import Title from "../../component/Title.jsx"; |
5 |
-import Map from "../../component/chart/Map.jsx"; |
|
11 |
+/* import Map from "../../component/chart/Map.jsx"; */ |
|
6 | 12 |
import Chart5 from "../../component/chart/Chart5.jsx"; |
7 | 13 |
import Chart2_govern from "../../component/chart/Chart2_govern.jsx"; |
8 | 14 |
import Donut1_govern from "../../component/chart/Donut1_govern.jsx"; |
... | ... | @@ -13,151 +19,138 @@ |
13 | 19 |
import MedicationIcon from '@mui/icons-material/Medication'; |
14 | 20 |
import ElderlyIcon from '@mui/icons-material/Elderly'; |
15 | 21 |
|
22 |
+ |
|
23 |
+import "leaflet/dist/leaflet.css"; |
|
24 |
+ |
|
16 | 25 |
export default function Main_government() { |
17 | 26 |
|
18 |
- //전역 변수 저장 객체 |
|
19 |
- const state = useSelector((state) => {return state}); |
|
27 |
+ //전역 변수 저장 객체 |
|
28 |
+ const state = useSelector((state) => {return state}); |
|
20 | 29 |
|
21 |
- const [cityName, setCityName] = useState("군위군"); |
|
30 |
+ const [cityName, setCityName] = useState(state.loginUser['government_name']); |
|
22 | 31 |
|
23 |
- React.useEffect(() => { |
|
24 |
- setCityName(state.loginUser['government_name']); |
|
25 |
- }, []); |
|
32 |
+ //대상자(시니어) 목록 조회 |
|
33 |
+ const [senior, setSenior] = React.useState({userList: [], userListCount: 0}); |
|
34 |
+ const seniorSelectList = () => { |
|
35 |
+ fetch("/user/userSelectList.json", { |
|
36 |
+ method: "POST", |
|
37 |
+ headers: { |
|
38 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
39 |
+ }, |
|
40 |
+ body: JSON.stringify({ |
|
41 |
+ 'government_id': state.loginUser['government_id'], |
|
42 |
+ 'agency_id': state.loginUser['agency_id'], |
|
43 |
+ 'authority': 'ROLE_SENIOR', |
|
44 |
+ }), |
|
45 |
+ }).then((response) => response.json()).then((data) => { |
|
46 |
+ console.log("대상자(시니어) 목록 조회 : ", data); |
|
47 |
+ setSenior(data); |
|
48 |
+ }).catch((error) => { |
|
49 |
+ console.log('seniorSelectList() /user/userSelectList.json error : ', error); |
|
50 |
+ }); |
|
51 |
+ } |
|
26 | 52 |
|
27 |
- // const tableHead = ["방문날짜", "방문사유", "방문 상세 사유"]; |
|
28 |
- // const Key = ["date", "reason", "detail_reason"]; |
|
29 |
- // const content = [ |
|
30 |
- // { |
|
31 |
- // date: "2022.12.12", |
|
32 |
- // reason: "어르신케어", |
|
33 |
- // detail_reason: "하루동안 미복약으로 방문. 방문시 두통을 호소하셔 병원 동행", |
|
34 |
- // }, |
|
35 |
- // ]; |
|
53 |
+ const iconHouse = new L.Icon({ |
|
54 |
+ iconUrl: '/client/resources/files/images/house.png', |
|
55 |
+ iconRetinaUrl: '/client/resources/files/images/house.png', |
|
56 |
+ iconSize: [20, 20], |
|
57 |
+ className: 'leaflet-background-radius-icon'//leaflet-div-icon |
|
58 |
+ }); |
|
36 | 59 |
|
37 |
- // //노인리스트 |
|
38 |
- // const tableHead2 = [ |
|
39 |
- // "이름", |
|
40 |
- // "요양등급", |
|
41 |
- // "생년월일", |
|
42 |
- // "연락처", |
|
43 |
- // "주소", |
|
44 |
- // "기저질환", |
|
45 |
- // ]; |
|
46 |
- // const Key2 = [ |
|
47 |
- // "name", |
|
48 |
- // "level_of_care", |
|
49 |
- // "birth", |
|
50 |
- // "phone", |
|
51 |
- // "address", |
|
52 |
- // "management_number", |
|
53 |
- // ]; |
|
54 |
- // const content2 = [ |
|
55 |
- // { |
|
56 |
- // name: "김복남", |
|
57 |
- // level_of_care: "1등급", |
|
58 |
- // birth: "1948.11.15", |
|
59 |
- // phone: "010-1234-5678", |
|
60 |
- // address: "경상북도 군위군 삼국유사면", |
|
61 |
- // management_number: "혈압", |
|
62 |
- // }, |
|
63 |
- // { |
|
64 |
- // name: "홍길동", |
|
65 |
- // level_of_care: "2등급", |
|
66 |
- // birth: "1948.05.18", |
|
67 |
- // phone: "010-3333-3333", |
|
68 |
- // address: "경상북도 군위군 삼국유사면", |
|
69 |
- // management_number: "당뇨", |
|
70 |
- // }, |
|
71 |
- // { |
|
72 |
- // name: "김말순", |
|
73 |
- // level_of_care: "3등급", |
|
74 |
- // birth: "1939.03.19", |
|
75 |
- // phone: "010-3333-4444", |
|
76 |
- // address: "경상북도 군위군 삼국유사면", |
|
77 |
- // management_number: "천식", |
|
78 |
- // }, |
|
79 |
- // { |
|
80 |
- // name: "신정길", |
|
81 |
- // level_of_care: "1등급", |
|
82 |
- // birth: "1945.05.19", |
|
83 |
- // phone: "010-3333-5555", |
|
84 |
- // address: "경상북도 군위군 삼국유사면", |
|
85 |
- // management_number: "폐렴", |
|
86 |
- // }, |
|
87 |
- // { |
|
88 |
- // name: "김정남", |
|
89 |
- // level_of_care: "1등급", |
|
90 |
- // birth: "1945.05.19", |
|
91 |
- // phone: "010-3333-6666", |
|
92 |
- // address: "경상북도 군위군 삼국유사면", |
|
93 |
- // management_number: "인지장애", |
|
94 |
- // }, |
|
95 |
- // ]; |
|
60 |
+ React.useEffect(() => { |
|
61 |
+ seniorSelectList(); |
|
62 |
+ }, []); |
|
96 | 63 |
|
97 |
- return ( |
|
98 |
- <main> |
|
99 |
- <div className="main-grid-government"> |
|
100 |
- <div className="sub-grid-government"> |
|
101 |
- <ul className="content-box statistics-govern" background="#f7acba"> |
|
102 |
- <li> |
|
103 |
- <p><ElderlyIcon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#bf0629", borderRadius:"50px" }}/></p> |
|
104 |
- <p>{cityName} 전체 대상자</p> |
|
105 |
- <p>30</p> |
|
106 |
- </li> |
|
64 |
+ |
|
65 |
+ return ( |
|
66 |
+ <main> |
|
67 |
+ <div className="main-grid-government"> |
|
68 |
+ <div className="sub-grid-government"> |
|
69 |
+ <ul className="content-box statistics-govern" background="#f7acba"> |
|
70 |
+ <li> |
|
71 |
+ <p><ElderlyIcon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#bf0629", borderRadius:"50px" }}/></p> |
|
72 |
+ <p>{cityName} 전체 대상자</p> |
|
73 |
+ <p>30</p> |
|
74 |
+ </li> |
|
75 |
+ </ul> |
|
76 |
+ <ul className="content-box statistics-govern" background="#8ef3d1"> |
|
77 |
+ <li> |
|
78 |
+ <p><MedicationIcon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#076143", borderRadius:"50px" }}/></p> |
|
79 |
+ <p>{cityName} 미복약 위험 대상자</p> |
|
80 |
+ <p>11</p> |
|
81 |
+ </li> |
|
107 | 82 |
</ul> |
108 |
- <ul className="content-box statistics-govern" background="#8ef3d1"> |
|
109 |
- <li> |
|
110 |
- <p><MedicationIcon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#076143", borderRadius:"50px" }}/></p> |
|
111 |
- <p>{cityName} 미복약 위험 대상자</p> |
|
112 |
- <p>11</p> |
|
113 |
- </li> |
|
114 |
- </ul> |
|
115 |
- <ul className="content-box statistics-govern" background="#ebe7b9" > |
|
116 |
- <li> |
|
117 |
- <p><DeviceThermostatIcon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#f1de05", borderRadius:"50px" }}/></p> |
|
118 |
- <p>{cityName} 댁내 온도 위험 대상자</p> |
|
119 |
- <p>7</p> |
|
120 |
- </li> |
|
121 |
- </ul> |
|
122 |
- <ul className="content-box statistics-govern" background="#5f9af3"> |
|
123 |
- <li> |
|
124 |
- <p><BatteryCharging20Icon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#5f9af3", borderRadius:"50px" }}/></p> |
|
125 |
- <p>{cityName} 배터리 부족 대상자 </p> |
|
126 |
- <p>13</p> |
|
127 |
- </li> |
|
128 |
- </ul> |
|
129 |
- </div> |
|
130 |
- <div className="content-box combine-left-government combine-bottom-government2 main-main"> |
|
131 |
- <div className="flex"> |
|
132 |
- <Title title={"지역별 케어 대상자 분포 현황"} explanation={"지역 선택 시 해당 지역의 대상자리스트가 보여집니다."} /> |
|
133 |
- </div> |
|
134 |
- <Map setCityName={setCityName} /> |
|
135 |
- </div> |
|
136 |
- <div className="content-box combine-all-government combine-bottom-government2"> |
|
137 |
- <div className="flex"> |
|
138 |
- <Title title={`${cityName} 월별 방문 횟수`} explanation={"최근 6개월간 방문 횟수의 변화를 확인할 수 있습니다."} /> |
|
139 |
- </div> |
|
140 |
- <RowChart_govern /> |
|
141 |
- </div> |
|
142 |
- <div className="content-box combine-left-government2"> |
|
143 |
- <div className="flex"> |
|
144 |
- <Title title={`${cityName} 복용률 평균`} explanation={"해당 지역의 대상자 복용률이 그래프로 보여집니다."} /> |
|
145 |
- </div> |
|
146 |
- <Chart2_govern /> |
|
147 |
- </div> |
|
148 |
- <div className="content-box combine-right-government2"> |
|
149 |
- <div className="flex"> |
|
150 |
- <Title title={`기관별 대상자 등록 현황`} explanation={"약상자 사용자의 데이터 차트가 보여집니다."} /> |
|
151 |
- </div> |
|
152 |
- <Chart5 /> |
|
153 |
- </div> |
|
154 |
- <div className="content-box combine-right-government"> |
|
155 |
- <div className="flex"> |
|
156 |
- <Title title={`기관별 약상자 사용 현황`} explanation={""} /> |
|
157 |
- </div> |
|
158 |
- <Donut1_govern /> |
|
159 |
- </div> |
|
160 |
- </div> |
|
161 |
- </main> |
|
162 |
- ); |
|
83 |
+ <ul className="content-box statistics-govern" background="#ebe7b9" > |
|
84 |
+ <li> |
|
85 |
+ <p><DeviceThermostatIcon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#f1de05", borderRadius:"50px" }}/></p> |
|
86 |
+ <p>{cityName} 댁내 온도 위험 대상자</p> |
|
87 |
+ <p>7</p> |
|
88 |
+ </li> |
|
89 |
+ </ul> |
|
90 |
+ <ul className="content-box statistics-govern" background="#5f9af3"> |
|
91 |
+ <li> |
|
92 |
+ <p><BatteryCharging20Icon sx={{ width: "50px", height: "50px", color: "#ffffff", background:"#5f9af3", borderRadius:"50px" }}/></p> |
|
93 |
+ <p>{cityName} 배터리 부족 대상자 </p> |
|
94 |
+ <p>13</p> |
|
95 |
+ </li> |
|
96 |
+ </ul> |
|
97 |
+ </div> |
|
98 |
+ <div className="content-box combine-left-government combine-bottom-government2 main-main"> |
|
99 |
+ <div className="flex"> |
|
100 |
+ <Title title={"지역별 케어 대상자 분포 현황"} explanation={"지역 선택 시 해당 지역의 대상자리스트가 보여집니다."} /> |
|
101 |
+ </div> |
|
102 |
+ <div style={{height: 'calc(100% - 60px)'}}> |
|
103 |
+ <MapContainer center={latLng(35.8713802646197, 128.601805491072)} zoom={13} scrollWheelZoom={true} style={{height: '100%'}}> |
|
104 |
+ <TileLayer |
|
105 |
+ attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' |
|
106 |
+ url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" |
|
107 |
+ /> |
|
108 |
+ {/* <Marker position={[128.601405491072, 35.8913802646197]}> |
|
109 |
+ <Popup> |
|
110 |
+ A pretty CSS3 popup. <br /> Easily customizable. |
|
111 |
+ </Popup> |
|
112 |
+ </Marker> */} |
|
113 |
+ |
|
114 |
+ <LayerGroup> |
|
115 |
+ {senior.userList.map((item, idx) => {return ( |
|
116 |
+ <Marker position={[item['y'], item['x']]} icon={iconHouse}> |
|
117 |
+ <Popup> |
|
118 |
+ <div> |
|
119 |
+ {item['user_name']}({item['user_birth']} - {item['user_gender']}) |
|
120 |
+ </div> |
|
121 |
+ </Popup> |
|
122 |
+ </Marker> |
|
123 |
+ )})} |
|
124 |
+ </LayerGroup> |
|
125 |
+ </MapContainer> |
|
126 |
+ </div> |
|
127 |
+ {/* <Map setCityName={setCityName} /> */} |
|
128 |
+ </div> |
|
129 |
+ <div className="content-box combine-all-government combine-bottom-government2"> |
|
130 |
+ <div className="flex"> |
|
131 |
+ <Title title={`${cityName} 월별 방문 횟수`} explanation={"최근 6개월간 방문 횟수의 변화를 확인할 수 있습니다."} /> |
|
132 |
+ </div> |
|
133 |
+ <RowChart_govern /> |
|
134 |
+ </div> |
|
135 |
+ <div className="content-box combine-left-government2"> |
|
136 |
+ <div className="flex"> |
|
137 |
+ <Title title={`${cityName} 복용률 평균`} explanation={"해당 지역의 대상자 복용률이 그래프로 보여집니다."} /> |
|
138 |
+ </div> |
|
139 |
+ <Chart2_govern /> |
|
140 |
+ </div> |
|
141 |
+ <div className="content-box combine-right-government2"> |
|
142 |
+ <div className="flex"> |
|
143 |
+ <Title title={`기관별 대상자 등록 현황`} explanation={"약상자 사용자의 데이터 차트가 보여집니다."} /> |
|
144 |
+ </div> |
|
145 |
+ <Chart5 /> |
|
146 |
+ </div> |
|
147 |
+ <div className="content-box combine-right-government"> |
|
148 |
+ <div className="flex"> |
|
149 |
+ <Title title={`기관별 약상자 사용 현황`} explanation={""} /> |
|
150 |
+ </div> |
|
151 |
+ <Donut1_govern /> |
|
152 |
+ </div> |
|
153 |
+ </div> |
|
154 |
+ </main> |
|
155 |
+ ); |
|
163 | 156 |
} |
--- client/views/pages/senior_management/SeniorEdit.jsx
+++ client/views/pages/senior_management/SeniorEdit.jsx
... | ... | @@ -4,6 +4,9 @@ |
4 | 4 |
import SubTitle from "../../component/SubTitle.jsx"; |
5 | 5 |
|
6 | 6 |
import CommonUtil from "../../../resources/js/CommonUtil.js"; |
7 |
+import {JUSO_API_KEY, JUSO_CORRD_API_KEY} from "../../../../Global.js"; |
|
8 |
+ |
|
9 |
+import proj4 from "proj4"; |
|
7 | 10 |
|
8 | 11 |
export default function SeniorEdit() { |
9 | 12 |
const navigate = useNavigate(); |
... | ... | @@ -190,6 +193,12 @@ |
190 | 193 |
return false; |
191 | 194 |
} |
192 | 195 |
|
196 |
+ if (CommonUtil.isEmpty(senior['zip_no']) == true) { |
|
197 |
+ seniorRef.current['user_address'].focus(); |
|
198 |
+ alert("검색을 통해 주소를 선택해 주세요."); |
|
199 |
+ return false; |
|
200 |
+ } |
|
201 |
+ |
|
193 | 202 |
return true; |
194 | 203 |
} |
195 | 204 |
//시니어 등록 |
... | ... | @@ -216,6 +225,79 @@ |
216 | 225 |
console.log('seniorUpdate() /user/seniorUpdate.json error : ', error); |
217 | 226 |
}); |
218 | 227 |
} |
228 |
+ |
|
229 |
+ |
|
230 |
+ //주소 검색 결과 객체 |
|
231 |
+ const [jusoList, setJusoList] = React.useState({ |
|
232 |
+ common: { |
|
233 |
+ countPerPage: 10, |
|
234 |
+ currentPage: 1, |
|
235 |
+ errorCode: '0', |
|
236 |
+ errorMessage: '정상', |
|
237 |
+ totalCount: 0 |
|
238 |
+ }, juso: [], |
|
239 |
+ }); |
|
240 |
+ //주소 검색 |
|
241 |
+ const jusoSearch = (currentPage) => { |
|
242 |
+ if (CommonUtil.isEmpty(senior['user_address']) == true) { |
|
243 |
+ seniorRef.current['user_address'].focus(); |
|
244 |
+ alert("주소를 입력해 주세요."); |
|
245 |
+ return false; |
|
246 |
+ } |
|
247 |
+ // console.log("check done"); |
|
248 |
+ let url = 'https://business.juso.go.kr/addrlink/addrLinkApi.do' |
|
249 |
+ url += `?currentPage=${CommonUtil.isEmpty(currentPage) ? 1 : currentPage}` |
|
250 |
+ url += '&countPerPage=10' |
|
251 |
+ url += '&resultType=json' |
|
252 |
+ url += `&keyword=${senior['user_address']}` |
|
253 |
+ url += `&confmKey=${JUSO_API_KEY}`; |
|
254 |
+ fetch(url, { |
|
255 |
+ method: "GET", |
|
256 |
+ }).then((response) => response.json()).then((data) => { |
|
257 |
+ console.log("주소 검색 결과(건수) : ", data); |
|
258 |
+ setJusoList(data.results); |
|
259 |
+ if (data.results.common.errorCode != '0') { |
|
260 |
+ alert(data.results.common.errorMessage); |
|
261 |
+ } else { |
|
262 |
+ if (CommonUtil.isEmpty(data.results.juso)) { |
|
263 |
+ alert('조회된 주소 정보가 없습니다.'); |
|
264 |
+ } |
|
265 |
+ } |
|
266 |
+ }).catch((error) => { |
|
267 |
+ console.log('jusoSearch() : ', error); |
|
268 |
+ }); |
|
269 |
+ }; |
|
270 |
+ |
|
271 |
+ const grs80 = "+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"; |
|
272 |
+ const wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; |
|
273 |
+ //주소 정보 활용 좌표 검색 |
|
274 |
+ const coordSearch = () => { |
|
275 |
+ console.log("check senior : ", senior); |
|
276 |
+ const vm = this; |
|
277 |
+ let url = 'https://business.juso.go.kr/addrlink/addrCoordApi.do' |
|
278 |
+ url += `?admCd=${senior['adm_cd']}` |
|
279 |
+ url += `&rnMgtSn=${senior['rn_mgt_sn']}` |
|
280 |
+ url += `&udrtYn=${senior['udrt_yn']}` |
|
281 |
+ url += `&buldMnnm=${senior['buld_mnnm']}` |
|
282 |
+ url += `&buldSlno=${senior['buld_slno']}` |
|
283 |
+ url += '&resultType=json' |
|
284 |
+ url += `&confmKey=${JUSO_CORRD_API_KEY}`; |
|
285 |
+ fetch(url, { |
|
286 |
+ method: "GET", |
|
287 |
+ }).then((response) => response.json()).then((data) => { |
|
288 |
+ console.log("주소 정보 활용 좌표 검색 결과(건수) : ", data); |
|
289 |
+ //setJusoList(data.results); |
|
290 |
+ if (data.results.common.errorCode == '0' && CommonUtil.isEmpty(data.results.juso) == false) { |
|
291 |
+ let grs80Point = [parseFloat(data.results.juso[0].entX), parseFloat(data.results.juso[0].entY)]; |
|
292 |
+ let wgs84Point = proj4(grs80, wgs84).forward(grs80Point); |
|
293 |
+ senior['x'] = wgs84Point[0]; |
|
294 |
+ senior['y'] = wgs84Point[1]; |
|
295 |
+ setSenior({...senior}); |
|
296 |
+ } |
|
297 |
+ }).catch((error) => { |
|
298 |
+ console.log('jusoSearch() : ', error); |
|
299 |
+ }); |
|
300 |
+ }; |
|
219 | 301 |
|
220 | 302 |
|
221 | 303 |
//Mounted |
... | ... | @@ -303,14 +385,15 @@ |
303 | 385 |
<tr> |
304 | 386 |
<th><span style={{color : "red"}}>*</span>연락처</th> |
305 | 387 |
<td colSpan={3}> |
306 |
- <input type="number" maxLength="11" |
|
388 |
+ <input type="number" maxLength="11" disabled |
|
307 | 389 |
value={senior['user_phonenumber']} |
308 | 390 |
onChange={(e) => {seniorValueChange('user_phonenumber', e.target.value)}} |
309 | 391 |
ref={el => seniorRef.current['user_phonenumber'] = el} |
310 | 392 |
/> |
311 | 393 |
</td> |
312 | 394 |
</tr> |
313 |
- <tr> |
|
395 |
+ |
|
396 |
+ {/* <tr> |
|
314 | 397 |
<th><span style={{color : "red"}}>*</span>주소</th> |
315 | 398 |
<td colSpan={3}> |
316 | 399 |
<input type="text" |
... | ... | @@ -319,7 +402,48 @@ |
319 | 402 |
ref={el => seniorRef.current['user_address'] = el} |
320 | 403 |
/> |
321 | 404 |
</td> |
405 |
+ </tr> */} |
|
406 |
+ <tr> |
|
407 |
+ <th><span style={{color : "red"}}>*</span>주소</th> |
|
408 |
+ <td colSpan={3}> |
|
409 |
+ <div> |
|
410 |
+ <input type="text" style={{width: 'calc(100% - 160px)'}} |
|
411 |
+ value={senior['user_address']} disabled={CommonUtil.isEmpty(senior['zip_no']) == false} |
|
412 |
+ onChange={(e) => {seniorValueChange('user_address', e.target.value)}} |
|
413 |
+ onKeyUp={(e) => {e.key == 'Enter' ? jusoSearch() : null}} |
|
414 |
+ ref={el => seniorRef.current['user_address'] = el} |
|
415 |
+ /> |
|
416 |
+ {CommonUtil.isEmpty(senior['zip_no']) |
|
417 |
+ ? <button className={"red-btn btn-large"} onClick={() => {jusoSearch()}}>주소검색</button> |
|
418 |
+ : <button className={"gray-btn btn-large"} onClick={() => {seniorValueChange('zip_no', null)}}>다시검색</button> |
|
419 |
+ } |
|
420 |
+ </div> |
|
421 |
+ {CommonUtil.isEmpty(jusoList.juso) == false && CommonUtil.isEmpty(senior['zip_no']) ? |
|
422 |
+ <div> |
|
423 |
+ <ul className="list-box" style={{width: '100%'}}> |
|
424 |
+ {CommonUtil.isEmpty(jusoList.juso) == false ? jusoList.juso.map((item, idx) => {return ( |
|
425 |
+ <li className={senior['zip_no'] == item['zipNo'] ? 'active' : null} onClick={() => { |
|
426 |
+ senior['zip_no'] = item['zipNo']; senior['adm_cd'] = item['admCd']; |
|
427 |
+ senior['rn_mgt_sn'] = item['rnMgtSn']; senior['bd_mgt_sn'] = item['bdMgtSn']; |
|
428 |
+ senior['siNsi_nmm'] = item['siNm']; senior['sgg_nm'] = item['sggNm']; |
|
429 |
+ senior['emd_nm'] = item['emdNm']; senior['li_nm'] = item['liNm']; |
|
430 |
+ senior['rn'] = item['rn']; senior['emd_no'] = item['emdNo']; |
|
431 |
+ senior['hemd_nm'] = item['hemdNm']; senior['road_addr'] = item['roadAddr']; |
|
432 |
+ senior['buld_mnnm'] = item['buldMnnm']; senior['buld_slno'] = item['buldSlno']; |
|
433 |
+ senior['user_address'] = item['roadAddr']; senior['udrt_yn'] = item['udrtYn']; |
|
434 |
+ setSenior({...senior}); coordSearch(); |
|
435 |
+ }}> |
|
436 |
+ <span style={{fontWeight: 600}}>[지번]</span> {item['jibunAddr']} |
|
437 |
+ <br/> |
|
438 |
+ <span style={{fontWeight: 600}}>[도로명]</span> {item['roadAddr']} |
|
439 |
+ </li> |
|
440 |
+ )}): null} |
|
441 |
+ </ul> |
|
442 |
+ </div> |
|
443 |
+ : null} |
|
444 |
+ </td> |
|
322 | 445 |
</tr> |
446 |
+ |
|
323 | 447 |
<tr> |
324 | 448 |
<th>필요 복약</th> |
325 | 449 |
<td className="medicationTime-td"> |
--- client/views/pages/user_management/AgencySeniorSelect.jsx
+++ client/views/pages/user_management/AgencySeniorSelect.jsx
... | ... | @@ -410,7 +410,7 @@ |
410 | 410 |
</select> |
411 | 411 |
<input type="text" className="senior-search" value={search.searchText} |
412 | 412 |
onChange={(e) => {search.searchText = e.target.value; setSearch({...search});}} |
413 |
- onKeyUp={(e) => searchingEnter(e)}/> |
|
413 |
+ onKeyUp={(e) => searchingEnter(e.key)}/> |
|
414 | 414 |
<button className="btn-small gray-btn" onClick={searching}>검색</button> |
415 | 415 |
</div> |
416 | 416 |
|
--- node_modules/.package-lock.json
+++ node_modules/.package-lock.json
... | ... | @@ -1753,6 +1753,16 @@ |
1753 | 1753 |
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", |
1754 | 1754 |
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" |
1755 | 1755 |
}, |
1756 |
+ "node_modules/@react-leaflet/core": { |
|
1757 |
+ "version": "2.1.0", |
|
1758 |
+ "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", |
|
1759 |
+ "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", |
|
1760 |
+ "peerDependencies": { |
|
1761 |
+ "leaflet": "^1.9.0", |
|
1762 |
+ "react": "^18.0.0", |
|
1763 |
+ "react-dom": "^18.0.0" |
|
1764 |
+ } |
|
1765 |
+ }, |
|
1756 | 1766 |
"node_modules/@reduxjs/toolkit": { |
1757 | 1767 |
"version": "1.9.3", |
1758 | 1768 |
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", |
... | ... | @@ -6011,6 +6021,11 @@ |
6011 | 6021 |
"graceful-fs": "^4.1.9" |
6012 | 6022 |
} |
6013 | 6023 |
}, |
6024 |
+ "node_modules/leaflet": { |
|
6025 |
+ "version": "1.9.3", |
|
6026 |
+ "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz", |
|
6027 |
+ "integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==" |
|
6028 |
+ }, |
|
6014 | 6029 |
"node_modules/levn": { |
6015 | 6030 |
"version": "0.3.0", |
6016 | 6031 |
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", |
... | ... | @@ -6197,6 +6212,11 @@ |
6197 | 6212 |
"engines": { |
6198 | 6213 |
"node": ">= 0.6" |
6199 | 6214 |
} |
6215 |
+ }, |
|
6216 |
+ "node_modules/mgrs": { |
|
6217 |
+ "version": "1.0.0", |
|
6218 |
+ "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", |
|
6219 |
+ "integrity": "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA==" |
|
6200 | 6220 |
}, |
6201 | 6221 |
"node_modules/micromatch": { |
6202 | 6222 |
"version": "2.3.11", |
... | ... | @@ -7136,6 +7156,15 @@ |
7136 | 7156 |
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", |
7137 | 7157 |
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" |
7138 | 7158 |
}, |
7159 |
+ "node_modules/proj4": { |
|
7160 |
+ "version": "2.9.0", |
|
7161 |
+ "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.9.0.tgz", |
|
7162 |
+ "integrity": "sha512-BoDXEzCVnRJVZoOKA0QHTFtYoE8lUxtX1jST38DJ8U+v1ixY70Kpwi0Llu6YqSWEH2xqu4XMEBNGcgeRIEywoA==", |
|
7163 |
+ "dependencies": { |
|
7164 |
+ "mgrs": "1.0.0", |
|
7165 |
+ "wkt-parser": "^1.3.1" |
|
7166 |
+ } |
|
7167 |
+ }, |
|
7139 | 7168 |
"node_modules/prop-types": { |
7140 | 7169 |
"version": "15.8.1", |
7141 | 7170 |
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", |
... | ... | @@ -7347,6 +7376,19 @@ |
7347 | 7376 |
"peerDependencies": { |
7348 | 7377 |
"react": ">=16.9.0", |
7349 | 7378 |
"react-dom": ">=16.9.0" |
7379 |
+ } |
|
7380 |
+ }, |
|
7381 |
+ "node_modules/react-leaflet": { |
|
7382 |
+ "version": "4.2.1", |
|
7383 |
+ "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", |
|
7384 |
+ "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", |
|
7385 |
+ "dependencies": { |
|
7386 |
+ "@react-leaflet/core": "^2.1.0" |
|
7387 |
+ }, |
|
7388 |
+ "peerDependencies": { |
|
7389 |
+ "leaflet": "^1.9.0", |
|
7390 |
+ "react": "^18.0.0", |
|
7391 |
+ "react-dom": "^18.0.0" |
|
7350 | 7392 |
} |
7351 | 7393 |
}, |
7352 | 7394 |
"node_modules/react-lifecycles-compat": { |
... | ... | @@ -9307,6 +9349,11 @@ |
9307 | 9349 |
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", |
9308 | 9350 |
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" |
9309 | 9351 |
}, |
9352 |
+ "node_modules/wkt-parser": { |
|
9353 |
+ "version": "1.3.2", |
|
9354 |
+ "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.2.tgz", |
|
9355 |
+ "integrity": "sha512-A26BOOo7sHAagyxG7iuRhnKMO7Q3mEOiOT4oGUmohtN/Li5wameeU4S6f8vWw6NADTVKljBs8bzA8JPQgSEMVQ==" |
|
9356 |
+ }, |
|
9310 | 9357 |
"node_modules/wmf": { |
9311 | 9358 |
"version": "1.0.2", |
9312 | 9359 |
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", |
--- package-lock.json
+++ package-lock.json
... | ... | @@ -31,16 +31,19 @@ |
31 | 31 |
"g3": "^0.2.37", |
32 | 32 |
"http": "^0.0.1-security", |
33 | 33 |
"https": "^1.0.0", |
34 |
+ "leaflet": "^1.9.3", |
|
34 | 35 |
"moment": "^2.29.4", |
35 | 36 |
"mysql": "2.18.1", |
36 | 37 |
"oracledb": "5.5.0", |
37 | 38 |
"pg": "8.8.0", |
38 |
- "react": "18.2.0", |
|
39 |
+ "proj4": "^2.9.0", |
|
40 |
+ "react": "^18.2.0", |
|
39 | 41 |
"react-calendar": "^4.0.0", |
40 | 42 |
"react-chartjs-2": "^5.2.0", |
41 |
- "react-dom": "18.2.0", |
|
43 |
+ "react-dom": "^18.2.0", |
|
42 | 44 |
"react-is": "18.2.0", |
43 | 45 |
"react-kakao-maps-sdk": "^1.1.5", |
46 |
+ "react-leaflet": "^4.2.1", |
|
44 | 47 |
"react-redux": "^8.0.5", |
45 | 48 |
"react-router": "6.3.0", |
46 | 49 |
"react-router-dom": "6.3.0", |
... | ... | @@ -1806,6 +1809,16 @@ |
1806 | 1809 |
"version": "1.1.0", |
1807 | 1810 |
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", |
1808 | 1811 |
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" |
1812 |
+ }, |
|
1813 |
+ "node_modules/@react-leaflet/core": { |
|
1814 |
+ "version": "2.1.0", |
|
1815 |
+ "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", |
|
1816 |
+ "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", |
|
1817 |
+ "peerDependencies": { |
|
1818 |
+ "leaflet": "^1.9.0", |
|
1819 |
+ "react": "^18.0.0", |
|
1820 |
+ "react-dom": "^18.0.0" |
|
1821 |
+ } |
|
1809 | 1822 |
}, |
1810 | 1823 |
"node_modules/@reduxjs/toolkit": { |
1811 | 1824 |
"version": "1.9.3", |
... | ... | @@ -6111,6 +6124,11 @@ |
6111 | 6124 |
"graceful-fs": "^4.1.9" |
6112 | 6125 |
} |
6113 | 6126 |
}, |
6127 |
+ "node_modules/leaflet": { |
|
6128 |
+ "version": "1.9.3", |
|
6129 |
+ "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz", |
|
6130 |
+ "integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==" |
|
6131 |
+ }, |
|
6114 | 6132 |
"node_modules/levn": { |
6115 | 6133 |
"version": "0.3.0", |
6116 | 6134 |
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", |
... | ... | @@ -6297,6 +6315,11 @@ |
6297 | 6315 |
"engines": { |
6298 | 6316 |
"node": ">= 0.6" |
6299 | 6317 |
} |
6318 |
+ }, |
|
6319 |
+ "node_modules/mgrs": { |
|
6320 |
+ "version": "1.0.0", |
|
6321 |
+ "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", |
|
6322 |
+ "integrity": "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA==" |
|
6300 | 6323 |
}, |
6301 | 6324 |
"node_modules/micromatch": { |
6302 | 6325 |
"version": "2.3.11", |
... | ... | @@ -7242,6 +7265,15 @@ |
7242 | 7265 |
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", |
7243 | 7266 |
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" |
7244 | 7267 |
}, |
7268 |
+ "node_modules/proj4": { |
|
7269 |
+ "version": "2.9.0", |
|
7270 |
+ "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.9.0.tgz", |
|
7271 |
+ "integrity": "sha512-BoDXEzCVnRJVZoOKA0QHTFtYoE8lUxtX1jST38DJ8U+v1ixY70Kpwi0Llu6YqSWEH2xqu4XMEBNGcgeRIEywoA==", |
|
7272 |
+ "dependencies": { |
|
7273 |
+ "mgrs": "1.0.0", |
|
7274 |
+ "wkt-parser": "^1.3.1" |
|
7275 |
+ } |
|
7276 |
+ }, |
|
7245 | 7277 |
"node_modules/prop-types": { |
7246 | 7278 |
"version": "15.8.1", |
7247 | 7279 |
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", |
... | ... | @@ -7453,6 +7485,19 @@ |
7453 | 7485 |
"peerDependencies": { |
7454 | 7486 |
"react": ">=16.9.0", |
7455 | 7487 |
"react-dom": ">=16.9.0" |
7488 |
+ } |
|
7489 |
+ }, |
|
7490 |
+ "node_modules/react-leaflet": { |
|
7491 |
+ "version": "4.2.1", |
|
7492 |
+ "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", |
|
7493 |
+ "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", |
|
7494 |
+ "dependencies": { |
|
7495 |
+ "@react-leaflet/core": "^2.1.0" |
|
7496 |
+ }, |
|
7497 |
+ "peerDependencies": { |
|
7498 |
+ "leaflet": "^1.9.0", |
|
7499 |
+ "react": "^18.0.0", |
|
7500 |
+ "react-dom": "^18.0.0" |
|
7456 | 7501 |
} |
7457 | 7502 |
}, |
7458 | 7503 |
"node_modules/react-lifecycles-compat": { |
... | ... | @@ -9413,6 +9458,11 @@ |
9413 | 9458 |
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", |
9414 | 9459 |
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" |
9415 | 9460 |
}, |
9461 |
+ "node_modules/wkt-parser": { |
|
9462 |
+ "version": "1.3.2", |
|
9463 |
+ "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.2.tgz", |
|
9464 |
+ "integrity": "sha512-A26BOOo7sHAagyxG7iuRhnKMO7Q3mEOiOT4oGUmohtN/Li5wameeU4S6f8vWw6NADTVKljBs8bzA8JPQgSEMVQ==" |
|
9465 |
+ }, |
|
9416 | 9466 |
"node_modules/wmf": { |
9417 | 9467 |
"version": "1.0.2", |
9418 | 9468 |
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", |
--- package.json
+++ package.json
... | ... | @@ -26,16 +26,19 @@ |
26 | 26 |
"g3": "^0.2.37", |
27 | 27 |
"http": "^0.0.1-security", |
28 | 28 |
"https": "^1.0.0", |
29 |
+ "leaflet": "^1.9.3", |
|
29 | 30 |
"moment": "^2.29.4", |
30 | 31 |
"mysql": "2.18.1", |
31 | 32 |
"oracledb": "5.5.0", |
32 | 33 |
"pg": "8.8.0", |
33 |
- "react": "18.2.0", |
|
34 |
+ "proj4": "^2.9.0", |
|
35 |
+ "react": "^18.2.0", |
|
34 | 36 |
"react-calendar": "^4.0.0", |
35 | 37 |
"react-chartjs-2": "^5.2.0", |
36 |
- "react-dom": "18.2.0", |
|
38 |
+ "react-dom": "^18.2.0", |
|
37 | 39 |
"react-is": "18.2.0", |
38 | 40 |
"react-kakao-maps-sdk": "^1.1.5", |
41 |
+ "react-leaflet": "^4.2.1", |
|
39 | 42 |
"react-redux": "^8.0.5", |
40 | 43 |
"react-router": "6.3.0", |
41 | 44 |
"react-router-dom": "6.3.0", |
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?