
230415 문진표 + 진료기록 + 심전도 + 혈압 + 공통파일업로드 처리(오류수정필요) 완성
@2026383f70375565bcf8873f8c1e4bc6f6e47711
+++ client/resources/css/common-file.css
... | ... | @@ -0,0 +1,26 @@ |
1 | +.file_input {text-align: left;} | |
2 | +.file_input label {position: relative; cursor: pointer; display: inline-block; vertical-align: middle; overflow: hidden; width:100px; height:28px; background:#888; border:1px solid #666; color:#fff; text-align: center; line-height: 28px; font-weight:400; transition-duration:0.5s;} | |
3 | +.file_input label:hover {background:#666; border-color:#444;} | |
4 | +.file_input label input {position: absolute; width:0; height: 0; overflow: hidden; display: none;} | |
5 | + | |
6 | +.file_edite_box {width:100%; position:relative; height:130px; margin-top: 10px;} | |
7 | +.file_edite_box.multiple-false {height:55px;} | |
8 | +.file_edite_box p {color: #A6A6A6; text-align: center; position: absolute; z-index:2; top: 0; bottom: 0; left: 0; right: 0; margin:auto; height: 33px; width: fit-content; font-weight: 500; padding:5px; cursor: pointer;} | |
9 | +.file_edite_box p > span {font-size:15px; margin:5px;} | |
10 | +.file_edite_box p > span.icon::before {content: ' \271A '} | |
11 | +.file_edite_box p.hidden {opacity: 0; z-index:3} | |
12 | +.file_edite_box .filename {margin-top: 0px; width:100%; display:inline-block; position:absolute; z-index:1; border:1px solid #ddd; padding: 10px; height:100%; overflow-y:scroll; left:0} | |
13 | + | |
14 | +.file_edite_box:hover > p {color: #7BA518;} | |
15 | +.file_edite_box:hover > .filename {border: 1px solid #7BA518;} | |
16 | + | |
17 | +.filename ul {background: #fff; text-align: left;} | |
18 | +.filename ul > li {width:100%; margin-bottom:8px; font-size:13px; color:#333;} | |
19 | +.filename ul > li > span {font-size:12px; margin-left:5px;} | |
20 | +.filename ul > li li {padding-left:20px; font-size:13px; color:#555;} | |
21 | +.filename ul > li li:before {content:'└'; color:#555; margin-right:5px;} | |
22 | + | |
23 | +.file_view {width:100%; position:relative; height:auto;} | |
24 | +.file_view > .marker {padding: 2px 10px; border: 1px solid #ddd; border-radius: 3px; margin-left: 3px; font-size: 12px; background: #f9f9f9; font-weight: 400; cursor: default;} | |
25 | + | |
26 | +.filename a {cursor: default !important;}(No newline at end of file) |
--- client/resources/css/common.css
+++ client/resources/css/common.css
... | ... | @@ -344,7 +344,8 @@ |
344 | 344 |
} |
345 | 345 |
|
346 | 346 |
.btn-large:last-child, |
347 |
-.btn-small:last-child { |
|
347 |
+.btn-small:last-child, |
|
348 |
+.btn-more-small { |
|
348 | 349 |
margin-right: 0; |
349 | 350 |
} |
350 | 351 |
|
+++ client/views/component/file/CommonFile.jsx
... | ... | @@ -0,0 +1,247 @@ |
1 | +import React from "react"; | |
2 | + | |
3 | +export default function CommonFile ({commonFileList, multiple, accept, isEdit}) { | |
4 | + | |
5 | + | |
6 | + let _multiple = (multiple == undefined || multiple == null) ? true : multiple; | |
7 | + let _isEdit = (isEdit == undefined || isEdit == null) ? true : isEdit; | |
8 | + let _accept = (accept == undefined || accept == null) ? null : accept; | |
9 | + | |
10 | + const [componentFileList, setComponentFileList] = React.useState(commonFileList); | |
11 | + | |
12 | + const inputFile = React.useRef(); | |
13 | + | |
14 | + const fileChange = (eventFiles) => { | |
15 | + //console.log('event에서 발생한 파일 : ', eventFiles); | |
16 | + | |
17 | + //event에서 발생한 파일이 없을 때 -> return | |
18 | + if (eventFiles == false || eventFiles == null || eventFiles.length == 0) { | |
19 | + return; | |
20 | + } | |
21 | + | |
22 | + //파일 한 개만 선택 가능할 때, 기존 파일이 있을 때 -> 확인 메세지 출력 | |
23 | + if (_multiple == false && commonFileList.length > 0) { | |
24 | + //새 파일 사용 -> 기존 파일 삭제 | |
25 | + if (confirm('기 선택 파일을 제거하고 새로 선택한 파일로 사용하시겠습니까?')) { | |
26 | + commonFileList.splice(0, commonFileList.length); | |
27 | + } else {//사용 안함 -> input file value(선택된 새파일) 제거 | |
28 | + inputFile.current.value = null; | |
29 | + return; | |
30 | + } | |
31 | + } | |
32 | + | |
33 | + | |
34 | + let loopSize = _multiple ? eventFiles.length : 1; | |
35 | + //console.log('_multiple ? eventFiles.length : ', loopSize); | |
36 | + for (var i = 0; i < loopSize; i++) { | |
37 | + //console.log('eventFiles['+i+'] : ', eventFiles[i]); | |
38 | + | |
39 | + commonFileList.push({ | |
40 | + commonFileGroupIdx: 0, | |
41 | + fileIdx: 0, | |
42 | + fileOriginName: getFileNameExceptExtension(eventFiles[i].name), | |
43 | + fileExtension: getFileExtension(eventFiles[i].name), | |
44 | + fileMaskName: null, | |
45 | + fileRelativePath: null, | |
46 | + fileAbsolutePath: null, | |
47 | + fileInsertDatetime: null, | |
48 | + fileSize: eventFiles[i].size, | |
49 | + fileDownloadCount: 0, | |
50 | + checkMessage: { | |
51 | + isSuccess: false, | |
52 | + message: '파일 검사 중', | |
53 | + status: 0 | |
54 | + } | |
55 | + }); | |
56 | + | |
57 | + //console.log('commonFileList : ', commonFileList); | |
58 | + //console.log('componentFileList : ', componentFileList); | |
59 | + setComponentFileList([...commonFileList]); | |
60 | + | |
61 | + //서버에 파일 업로드 후, 업로드된 내용 받아오기 | |
62 | + const currentCommonFileIndex = commonFileList.length - 1; | |
63 | + const currentLoopIndex = i; | |
64 | + serverUpload(eventFiles[i], (data) => { | |
65 | + commonFileList[currentCommonFileIndex] = data; | |
66 | + setComponentFileList([...commonFileList]); | |
67 | + | |
68 | + /* | |
69 | + * 마지막 파일 일 때, -> input file에 value 지워주기 | |
70 | + * 필요이유 : 같은 파일 선택시, onchange가 동작하지 않음); | |
71 | + * Callback에 넣은 이유 : 모든 처리완료 후, 지워줘야함 아니면, 처리 중간에 eventFiles애 값이 사라지는 현상이 발생함 | |
72 | + */ | |
73 | + if ((currentLoopIndex + 1) == loopSize) { | |
74 | + inputFile.current.value = null; | |
75 | + } | |
76 | + }); | |
77 | + } | |
78 | + }; | |
79 | + | |
80 | + //서버에 파일 업로드 | |
81 | + const serverUpload = (eventFile, callback, commonFileIndex) => { | |
82 | + //console.log('serverUpload eventFile : ', eventFile, ' commonFileIndex : ', commonFileIndex, ' commonFileList['+commonFileIndex+'] : ', commonFileList[commonFileIndex]); | |
83 | + | |
84 | + var formData = new FormData(); | |
85 | + formData.append('file', eventFile); | |
86 | + //console.log('formData : ', formData); | |
87 | + | |
88 | + fetch('/common/file/upload.file', { | |
89 | + method: "POST", | |
90 | + /* headers: { | |
91 | + 'Content-Type': 'multipart/form-data; charset=UTF-8' | |
92 | + }, */ | |
93 | + body: formData, | |
94 | + }).then((response) => response.json()).then((data) => { | |
95 | + console.log("setFileAndUpload in serverUpload - response data : ", data); | |
96 | + callback(data[0]); | |
97 | + }).catch((error) => { | |
98 | + console.log('serverUpload() /common/file/upload.file error : ', error); | |
99 | + }); | |
100 | + } | |
101 | + | |
102 | + //파일명에서 확장자 얻기 | |
103 | + const getFileExtension = (fileName) => { | |
104 | + if (fileName == undefined || fileName == null) { | |
105 | + return null; | |
106 | + } else { | |
107 | + const index = fileName.lastIndexOf("."); | |
108 | + if (index > -1) { | |
109 | + console.log('fileName.substring('+index+' + 1) : ', fileName.substring(index + 1)); | |
110 | + return fileName.substring(index + 1).toLowerCase(); | |
111 | + } else { | |
112 | + return null; | |
113 | + } | |
114 | + } | |
115 | + }; | |
116 | + | |
117 | + //파일명에서 확장자를 제외한 파일명 얻기 | |
118 | + const getFileNameExceptExtension = (fileName) => { | |
119 | + if (fileName == undefined || fileName == null) { | |
120 | + return null; | |
121 | + } else { | |
122 | + const index = fileName.lastIndexOf("."); | |
123 | + if (index > -1) { | |
124 | + console.log('fileName.substring(0, '+index+') : ', fileName.substring(0, index)); | |
125 | + return fileName.substring(0, index); | |
126 | + } else { | |
127 | + return null; | |
128 | + } | |
129 | + } | |
130 | + }; | |
131 | + | |
132 | + //적절한 파일 사이즈로 만들어주는 기능 | |
133 | + const getFileSize = (byteSize) => { | |
134 | + var result = byteSize + " bytes"; | |
135 | + // optional code for multiples approximation | |
136 | + var type = ["KB", "MB", "GB", "TB", "PB"]; | |
137 | + for (var i = 0, reSize = (byteSize / 1024); reSize > 1 && i < type.length; reSize /= 1024, i++) { | |
138 | + result = reSize.toFixed(3) + " " + type[i]; | |
139 | + } | |
140 | + return result; | |
141 | + } | |
142 | + | |
143 | + //파일 다운로드 | |
144 | + const fileDownload = (commonFile) => { | |
145 | + if (commonFile == undefined || commonFile.fileIdx == undefined | |
146 | + || commonFile.fileIdx == null || commonFile.fileIdx == 0) { | |
147 | + alert('서버에 업로드된 파일이 아닙니다.(파일다운로드 불가)'); | |
148 | + return; | |
149 | + } | |
150 | + | |
151 | + var formTag = document.createElement('form'); | |
152 | + formTag.action = "/common/file/download.file"; | |
153 | + formTag.method = "post"; | |
154 | + | |
155 | + var fileKeyInput = document.createElement('input'); | |
156 | + fileKeyInput.type = "hidden"; | |
157 | + fileKeyInput.name = "fileIdx"; | |
158 | + fileKeyInput.value = commonFile.fileIdx; | |
159 | + formTag.appendChild(fileKeyInput); | |
160 | + | |
161 | + document.body.appendChild(formTag); | |
162 | + formTag.submit(); | |
163 | + formTag.remove(); | |
164 | + }; | |
165 | + | |
166 | + //파일 삭제 | |
167 | + const fileDelete = (commonFile, idx) => { | |
168 | + if (commonFile == undefined || commonFile.fileIdx == undefined | |
169 | + || commonFile.fileIdx == null || commonFile.fileIdx == 0) { | |
170 | + commonFileList.splice(idx, 1); | |
171 | + setComponentFileList([...commonFileList]); | |
172 | + return; | |
173 | + } | |
174 | + | |
175 | + var formTag = document.createElement('form'); | |
176 | + formTag.action = "/common/file/delete.file"; | |
177 | + formTag.method = "post"; | |
178 | + | |
179 | + var fileKeyInput = document.createElement('input'); | |
180 | + fileKeyInput.type = "hidden"; | |
181 | + fileKeyInput.name = "fileIdx"; | |
182 | + fileKeyInput.value = commonFile.fileIdx; | |
183 | + formTag.appendChild(fileKeyInput); | |
184 | + | |
185 | + document.body.appendChild(formTag); | |
186 | + formTag.submit(); | |
187 | + formTag.remove(); | |
188 | + }; | |
189 | + | |
190 | + React.useEffect(() => { | |
191 | + console.log('==================================='); | |
192 | + console.log('commonFileList : ', commonFileList); | |
193 | + console.log('componentFileList : ', componentFileList); | |
194 | + console.log('==================================='); | |
195 | + console.log(''); | |
196 | + }, [componentFileList]) | |
197 | + | |
198 | + return ( | |
199 | + <div className="component-file-content" id="file-content"> | |
200 | + <div id="file_edite"> | |
201 | + | |
202 | + <div className="file_input"> | |
203 | + <label className="btn_lightblue" title="파일선택">파일선택 | |
204 | + <input type="file" ref={inputFile} multiple={_multiple} accept={_accept} | |
205 | + onChange={(e) => fileChange(e.target.files)}/> | |
206 | + </label> | |
207 | + </div> | |
208 | + | |
209 | + <div className={_multiple ? 'file_edite_box' : 'file_edite_box multiple-false'} | |
210 | + onDragOver={(e) => e.preventDefault()} | |
211 | + onDragEnter={(e) => e.preventDefault()} | |
212 | + onDrop={(e) => {e.preventDefault(); fileChange(e.dataTransfer.files);}}> | |
213 | + {componentFileList == null || componentFileList.length == 0 | |
214 | + ? <p onClick={() => {inputFile.current.click()}}> | |
215 | + <span className="icon"></span>파일을 끌어다 넣거나, 파일을 선택해주세요. | |
216 | + </p> | |
217 | + : null} | |
218 | + <div className="filename"> | |
219 | + <ul> | |
220 | + {componentFileList.map((item, idx) => {return ( | |
221 | + <li> | |
222 | + {/* 첨부파일 이미지 */} | |
223 | + | |
224 | + {/* 첨부파일 명 */} | |
225 | + <a>{item.fileOriginName}.{item.fileExtension} [{getFileSize(item.fileSize)}]</a> | |
226 | + | |
227 | + {/* 파일첨부 결과 메세지 */} | |
228 | + {item.checkMessage != null && item.checkMessage.message != null && item.checkMessage.message.length > 0 | |
229 | + ? <span className={item.checkMessage.isSuccess ? 'green' : 'red'}>({item.checkMessage.message})</span> | |
230 | + : null} | |
231 | + | |
232 | + {/* 파일 다운로드 버튼 */} | |
233 | + {item.fileIdx != null && item.fileIdx > 0 | |
234 | + ? <button className="btn-more-small gray-btn margin-left2" onClick={() => fileDownload(item)}>다운로드</button> | |
235 | + : null} | |
236 | + | |
237 | + {/* 파일 삭제 버튼 */} | |
238 | + <button className="btn-more-small red-btn margin-left2" onClick={() => fileDelete(item, idx)}>삭제</button> | |
239 | + </li> | |
240 | + )})} | |
241 | + </ul> | |
242 | + </div> | |
243 | + </div> | |
244 | + </div> | |
245 | + </div> | |
246 | + ) | |
247 | +} |
--- client/views/index.jsx
+++ client/views/index.jsx
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 |
import "../resources/css/reset.css"; |
18 | 18 |
import "../resources/css/layout.css"; |
19 | 19 |
import "../resources/css/common.css"; |
20 |
+import "../resources/css/common-file.css"; |
|
20 | 21 |
import "../resources/css/main.css"; |
21 | 22 |
import "../resources/css/responsive.css"; |
22 | 23 |
|
--- client/views/pages/healthcare/Medicalcare.jsx
+++ client/views/pages/healthcare/Medicalcare.jsx
... | ... | @@ -6,11 +6,8 @@ |
6 | 6 |
import SubTitle from "../../component/SubTitle.jsx"; |
7 | 7 |
import Modal from "../../component/Modal.jsx"; |
8 | 8 |
import DetailTitle from "../../component/DetailTitle.jsx"; |
9 |
-import Modal_Questionnaire from "../../component/Modal_Questionnaire.jsx"; |
|
10 |
-import Modal_MedicalHistory from "../../component/Modal_MedicalHistory.jsx"; |
|
11 |
-import Modal_Blood from "../../component/Modal_Blood.jsx"; |
|
12 |
-import Modal_ECG from "../../component/Modal_ECG.jsx"; |
|
13 | 9 |
import Pagination from "../../component/Pagination.jsx"; |
10 |
+import CommonFile from "../../component/file/CommonFile.jsx"; |
|
14 | 11 |
|
15 | 12 |
import CommonUtil from "../../../resources/js/CommonUtil.js"; |
16 | 13 |
|
... | ... | @@ -258,7 +255,6 @@ |
258 | 255 |
|
259 | 256 |
|
260 | 257 |
|
261 |
- |
|
262 | 258 |
/****************** 병원 진료 기록 (시작) ******************/ |
263 | 259 |
const hospitalMedicalRecordInit = { |
264 | 260 |
'senior_id': null, |
... | ... | @@ -293,6 +289,7 @@ |
293 | 289 |
return false; |
294 | 290 |
} |
295 | 291 |
|
292 |
+ return true; |
|
296 | 293 |
} |
297 | 294 |
|
298 | 295 |
|
... | ... | @@ -359,6 +356,33 @@ |
359 | 356 |
}); |
360 | 357 |
} |
361 | 358 |
|
359 |
+ //병원 진료 기록 삭제 |
|
360 |
+ const hospitalMedicalRecordDelete = () => { |
|
361 |
+ if (confirm('진료 기록을 삭제하시겠습니까?') == false) { |
|
362 |
+ return; |
|
363 |
+ } |
|
364 |
+ |
|
365 |
+ fetch("/hospital/hospitalMedicalRecordDelete.json", { |
|
366 |
+ method: "POST", |
|
367 |
+ headers: { |
|
368 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
369 |
+ }, |
|
370 |
+ body: JSON.stringify(hospitalMedicalRecord), |
|
371 |
+ }).then((response) => response.json()).then((data) => { |
|
372 |
+ console.log("병원 진료 기록 삭제 결과(건수) : ", data); |
|
373 |
+ if (data > 0) { |
|
374 |
+ setHospitalMedicalRecordInit(); |
|
375 |
+ hospitalMedicalRecordSelectList(); |
|
376 |
+ //closeModal2(); |
|
377 |
+ alert("삭제완료"); |
|
378 |
+ } else { |
|
379 |
+ alert("삭제에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
380 |
+ } |
|
381 |
+ }).catch((error) => { |
|
382 |
+ console.log('hospitalMedicalRecordDelete() /hospital/hospitalMedicalRecordDelete.json error : ', error); |
|
383 |
+ }); |
|
384 |
+ } |
|
385 |
+ |
|
362 | 386 |
//초기화 취소 |
363 | 387 |
const setHospitalMedicalRecordInit = () => { |
364 | 388 |
setHospitalMedicalRecord({...hospitalMedicalRecordInit}); |
... | ... | @@ -389,9 +413,401 @@ |
389 | 413 |
/****************** 병원 진료 기록 (종료) ******************/ |
390 | 414 |
|
391 | 415 |
|
392 |
- |
|
393 |
- const ecgSelectList = () => {}; |
|
394 |
- const bloodPressureSelectList = () => {}; |
|
416 |
+ |
|
417 |
+ /****************** 심전도 (시작) ******************/ |
|
418 |
+ const ecgInit = { |
|
419 |
+ 'senior_id': null, |
|
420 |
+ 'ecg_record_idx': null, |
|
421 |
+ 'bradycardia_count': 0, |
|
422 |
+ 'tachycardia_count': 0, |
|
423 |
+ 'max_heart_rate': 0.0, |
|
424 |
+ 'min_heart_rate': 0.0, |
|
425 |
+ 'abnormal_heart_rate': 0.0, |
|
426 |
+ 'average_heart_rate': 0.0, |
|
427 |
+ 'max_rr': 0.0, |
|
428 |
+ 'min_rr': 0.0, |
|
429 |
+ 'average_rr': 0.0, |
|
430 |
+ 'ecg_reading_date': CommonUtil.getDate(), |
|
431 |
+ 'ecg_finding_type': '', |
|
432 |
+ 'ecg_finding_content': '', |
|
433 |
+ 'agent_id': defaultUserId, |
|
434 |
+ 'medical_record_idx': null, |
|
435 |
+ 'common_group_file_idx': null, |
|
436 |
+ commonFileList: [],//심전도 업로드 파일 목록 |
|
437 |
+ |
|
438 |
+ isEdit: false,//직접 수정일 때, true (수정 or 등록 상관없음); |
|
439 |
+ }; |
|
440 |
+ //심전도 정보 |
|
441 |
+ const [ecg, setEcg] = React.useState({...ecgInit}); |
|
442 |
+ const ecgRef = React.useRef({...ecgInit}); |
|
443 |
+ |
|
444 |
+ //심전도 유효성 검사 |
|
445 |
+ const ecgValidation = () => { |
|
446 |
+ const target = ecg; |
|
447 |
+ const targetRef = ecgRef; |
|
448 |
+ |
|
449 |
+ if (CommonUtil.isEmpty(target['ecg_reading_date']) == true) { |
|
450 |
+ targetRef.current['ecg_reading_date'].focus(); |
|
451 |
+ alert("판독 소견 측정 일자를 선택해 주세요."); |
|
452 |
+ return false; |
|
453 |
+ } |
|
454 |
+ if (CommonUtil.isEmpty(target['ecg_finding_type']) == true) { |
|
455 |
+ targetRef.current['ecg_finding_type'].focus(); |
|
456 |
+ alert("판독 소견 측정 종류를 입력해 주세요."); |
|
457 |
+ return false; |
|
458 |
+ } |
|
459 |
+ if (CommonUtil.isEmpty(target['ecg_finding_content']) == true) { |
|
460 |
+ targetRef.current['ecg_finding_content'].focus(); |
|
461 |
+ alert("판독 소견 측정 내용을 입력해 주세요."); |
|
462 |
+ return false; |
|
463 |
+ } |
|
464 |
+ //파일 입력 |
|
465 |
+ if (target.isEdit == false) { |
|
466 |
+ if (CommonUtil.isEmpty(target['commonFileList']) == true) { |
|
467 |
+ //targetRef.current['commonFileList'].focus(); |
|
468 |
+ alert("심전도 측정 파일을 올려주세요."); |
|
469 |
+ return false; |
|
470 |
+ } |
|
471 |
+ } else {//직접 입력 |
|
472 |
+ if (CommonUtil.isEmpty(target['bradycardia_count']) == true) { |
|
473 |
+ targetRef.current['bradycardia_count'].focus(); |
|
474 |
+ alert("서맥 횟수를 입력해 주세요."); |
|
475 |
+ return false; |
|
476 |
+ } |
|
477 |
+ if (CommonUtil.isEmpty(target['tachycardia_count']) == true) { |
|
478 |
+ targetRef.current['tachycardia_count'].focus(); |
|
479 |
+ alert("빈맥 횟수 입력해 주세요."); |
|
480 |
+ return false; |
|
481 |
+ } |
|
482 |
+ if (CommonUtil.isEmpty(target['max_heart_rate']) == true) { |
|
483 |
+ targetRef.current['average_heart_rate'].focus(); |
|
484 |
+ alert("최대 심박수를 입력해 주세요."); |
|
485 |
+ return false; |
|
486 |
+ } |
|
487 |
+ if (CommonUtil.isEmpty(target['min_heart_rate']) == true) { |
|
488 |
+ targetRef.current['average_heart_rate'].focus(); |
|
489 |
+ alert("최소 심박수를 입력해 주세요."); |
|
490 |
+ return false; |
|
491 |
+ } |
|
492 |
+ if (CommonUtil.isEmpty(target['average_heart_rate']) == true) { |
|
493 |
+ targetRef.current['average_heart_rate'].focus(); |
|
494 |
+ alert("평균 심박수를 입력해 주세요."); |
|
495 |
+ return false; |
|
496 |
+ } |
|
497 |
+ if (CommonUtil.isEmpty(target['abnormal_heart_rate']) == true) { |
|
498 |
+ targetRef.current['abnormal_heart_rate'].focus(); |
|
499 |
+ alert("이상 심박수를 입력해 주세요."); |
|
500 |
+ return false; |
|
501 |
+ } |
|
502 |
+ if (CommonUtil.isEmpty(target['max_rr']) == true) { |
|
503 |
+ targetRef.current['max_rr'].focus(); |
|
504 |
+ alert("최대 R-R를 입력해 주세요."); |
|
505 |
+ return false; |
|
506 |
+ } |
|
507 |
+ if (CommonUtil.isEmpty(target['min_rr']) == true) { |
|
508 |
+ targetRef.current['min_rr'].focus(); |
|
509 |
+ alert("최소 R-R를 입력해 주세요."); |
|
510 |
+ return false; |
|
511 |
+ } |
|
512 |
+ if (CommonUtil.isEmpty(target['average_rr']) == true) { |
|
513 |
+ targetRef.current['average_rr'].focus(); |
|
514 |
+ alert("평균 R-R를 입력해 주세요."); |
|
515 |
+ return false; |
|
516 |
+ } |
|
517 |
+ } |
|
518 |
+ |
|
519 |
+ return true; |
|
520 |
+ } |
|
521 |
+ |
|
522 |
+ |
|
523 |
+ //심전도 등록 |
|
524 |
+ const ecgInsert = () => { |
|
525 |
+ if (ecgValidation() == false) { |
|
526 |
+ return; |
|
527 |
+ } |
|
528 |
+ |
|
529 |
+ ecg['senior_id'] = targetSenior['senior_id']; |
|
530 |
+ ecg['agent_id'] = defaultUserId; |
|
531 |
+ setEcg({...ecg}); |
|
532 |
+ |
|
533 |
+ fetch("/hospital/ecgInsert.json", { |
|
534 |
+ method: "POST", |
|
535 |
+ headers: { |
|
536 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
537 |
+ }, |
|
538 |
+ body: JSON.stringify(ecg), |
|
539 |
+ }).then((response) => response.json()).then((data) => { |
|
540 |
+ console.log("심전도 등록 결과(건수) : ", data); |
|
541 |
+ if (data > 0) { |
|
542 |
+ setEcgInit(); |
|
543 |
+ ecgSelectList(); |
|
544 |
+ //closeModal3(); |
|
545 |
+ alert("등록완료"); |
|
546 |
+ |
|
547 |
+ } else { |
|
548 |
+ alert("등록에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
549 |
+ } |
|
550 |
+ }).catch((error) => { |
|
551 |
+ console.log('ecgInsert() /hospital/ecgInsert.json error : ', error); |
|
552 |
+ }); |
|
553 |
+ } |
|
554 |
+ |
|
555 |
+ //심전도 수정 |
|
556 |
+ const ecgUpdate = () => { |
|
557 |
+ if (ecgValidation() == false) { |
|
558 |
+ return; |
|
559 |
+ } |
|
560 |
+ |
|
561 |
+ ecg['senior_id'] = targetSenior['senior_id']; |
|
562 |
+ ecg['agent_id'] = defaultUserId; |
|
563 |
+ setEcg({...ecg}); |
|
564 |
+ |
|
565 |
+ fetch("/hospital/ecgUpdate.json", { |
|
566 |
+ method: "POST", |
|
567 |
+ headers: { |
|
568 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
569 |
+ }, |
|
570 |
+ body: JSON.stringify(ecg), |
|
571 |
+ }).then((response) => response.json()).then((data) => { |
|
572 |
+ console.log("심전도 수정 결과(건수) : ", data); |
|
573 |
+ if (data > 0) { |
|
574 |
+ setEcgInit(); |
|
575 |
+ ecg.commonFileList = []; |
|
576 |
+ setEcg({...ecg}); |
|
577 |
+ ecgSelectList(); |
|
578 |
+ //closeModal3(); |
|
579 |
+ alert("수정완료"); |
|
580 |
+ } else { |
|
581 |
+ alert("수정에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
582 |
+ } |
|
583 |
+ }).catch((error) => { |
|
584 |
+ console.log('ecgUpdate() /hospital/ecgUpdate.json error : ', error); |
|
585 |
+ }); |
|
586 |
+ } |
|
587 |
+ |
|
588 |
+ //심전도 삭제 |
|
589 |
+ const ecgDelete = () => { |
|
590 |
+ if (confirm('심전도 판독 소견을 삭제하시겠습니까?') == false) { |
|
591 |
+ return; |
|
592 |
+ } |
|
593 |
+ |
|
594 |
+ fetch("/hospital/ecgDelete.json", { |
|
595 |
+ method: "POST", |
|
596 |
+ headers: { |
|
597 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
598 |
+ }, |
|
599 |
+ body: JSON.stringify(ecg), |
|
600 |
+ }).then((response) => response.json()).then((data) => { |
|
601 |
+ console.log("심전도 삭제 결과(건수) : ", data); |
|
602 |
+ if (data > 0) { |
|
603 |
+ setEcgInit(); |
|
604 |
+ ecg.commonFileList = []; |
|
605 |
+ setEcg({...ecg}); |
|
606 |
+ ecgSelectList(); |
|
607 |
+ //closeModal3(); |
|
608 |
+ alert("삭제완료"); |
|
609 |
+ } else { |
|
610 |
+ alert("삭제에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
611 |
+ } |
|
612 |
+ }).catch((error) => { |
|
613 |
+ console.log('ecgDelete() /hospital/ecgDelete.json error : ', error); |
|
614 |
+ }); |
|
615 |
+ } |
|
616 |
+ |
|
617 |
+ //초기화 취소 |
|
618 |
+ const setEcgInit = () => { |
|
619 |
+ setEcg({...ecgInit}); |
|
620 |
+ } |
|
621 |
+ |
|
622 |
+ //심전도 정보 |
|
623 |
+ const [ecgList, setEcgList] = React.useState({ecgList: [], ecgListCount:0, search: {currentPage: 1, perPage: 5}}); |
|
624 |
+ //심전도 목록 조회 |
|
625 |
+ const ecgSelectList = (currentPage) => { |
|
626 |
+ ecgList.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage; |
|
627 |
+ ecgList.search['senior_id'] = targetSenior['senior_id']; |
|
628 |
+ setEcgList({...ecgList}); |
|
629 |
+ |
|
630 |
+ fetch("/hospital/ecgSelectList.json", { |
|
631 |
+ method: "POST", |
|
632 |
+ headers: { |
|
633 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
634 |
+ }, |
|
635 |
+ body: JSON.stringify(ecgList.search), |
|
636 |
+ }).then((response) => response.json()).then((data) => { |
|
637 |
+ console.log("심전도 목록 조회 결과(건수) : ", data); |
|
638 |
+ data.search = ecgList.search; |
|
639 |
+ setEcgList(data); |
|
640 |
+ }).catch((error) => { |
|
641 |
+ console.log('ecgSelectList() /hospital/ecgSelectList.json error : ', error); |
|
642 |
+ }); |
|
643 |
+ } |
|
644 |
+ /****************** 심전도 기록 (종료) ******************/ |
|
645 |
+ |
|
646 |
+ |
|
647 |
+ |
|
648 |
+ /****************** 혈압 (시작) ******************/ |
|
649 |
+ const bloodPressureInit = { |
|
650 |
+ 'senior_id': null, |
|
651 |
+ 'blood_pressure_record_idx': null, |
|
652 |
+ 'max_blood_pressure': null, |
|
653 |
+ 'min_blood_pressure': null, |
|
654 |
+ 'pulse_rate': null, |
|
655 |
+ 'medical_record_idx': null, |
|
656 |
+ 'blood_pressure_record_date': CommonUtil.getDate(), |
|
657 |
+ 'agent_id': defaultUserId |
|
658 |
+ }; |
|
659 |
+ //혈압 정보 |
|
660 |
+ const [bloodPressure, setBloodPressure] = React.useState({...bloodPressureInit}); |
|
661 |
+ const bloodPressureRef = React.useRef({...bloodPressureInit}); |
|
662 |
+ |
|
663 |
+ //혈압 유효성 검사 |
|
664 |
+ const bloodPressureValidation = () => { |
|
665 |
+ const target = bloodPressure; |
|
666 |
+ const targetRef = bloodPressureRef; |
|
667 |
+ |
|
668 |
+ if (CommonUtil.isEmpty(target['blood_pressure_record_date']) == true) { |
|
669 |
+ targetRef.current['blood_pressure_record_date'].focus(); |
|
670 |
+ alert("진료 일자를 선택해 주세요."); |
|
671 |
+ return false; |
|
672 |
+ } |
|
673 |
+ if (CommonUtil.isEmpty(target['max_blood_pressure']) == true) { |
|
674 |
+ targetRef.current['max_blood_pressure'].focus(); |
|
675 |
+ alert("최고 혈압을 입력해 주세요."); |
|
676 |
+ return false; |
|
677 |
+ } |
|
678 |
+ if (CommonUtil.isEmpty(target['min_blood_pressure']) == true) { |
|
679 |
+ targetRef.current['min_blood_pressure'].focus(); |
|
680 |
+ alert("최저 혈압을 입력해 주세요."); |
|
681 |
+ return false; |
|
682 |
+ } |
|
683 |
+ if (CommonUtil.isEmpty(target['pulse_rate']) == true) { |
|
684 |
+ targetRef.current['pulse_rate'].focus(); |
|
685 |
+ alert("맥박수를 입력해 주세요."); |
|
686 |
+ return false; |
|
687 |
+ } |
|
688 |
+ |
|
689 |
+ return true; |
|
690 |
+ } |
|
691 |
+ |
|
692 |
+ |
|
693 |
+ //혈압 등록 |
|
694 |
+ const bloodPressureInsert = () => { |
|
695 |
+ if (bloodPressureValidation() == false) { |
|
696 |
+ return; |
|
697 |
+ } |
|
698 |
+ |
|
699 |
+ bloodPressure['senior_id'] = targetSenior['senior_id']; |
|
700 |
+ bloodPressure['agent_id'] = defaultUserId; |
|
701 |
+ setBloodPressure({...bloodPressure}); |
|
702 |
+ |
|
703 |
+ fetch("/hospital/bloodPressureInsert.json", { |
|
704 |
+ method: "POST", |
|
705 |
+ headers: { |
|
706 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
707 |
+ }, |
|
708 |
+ body: JSON.stringify(bloodPressure), |
|
709 |
+ }).then((response) => response.json()).then((data) => { |
|
710 |
+ console.log("혈압 등록 결과(건수) : ", data); |
|
711 |
+ if (data > 0) { |
|
712 |
+ setBloodPressureInit(); |
|
713 |
+ bloodPressureSelectList(); |
|
714 |
+ //closeModal2(); |
|
715 |
+ alert("등록완료"); |
|
716 |
+ |
|
717 |
+ } else { |
|
718 |
+ alert("등록에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
719 |
+ } |
|
720 |
+ }).catch((error) => { |
|
721 |
+ console.log('bloodPressureInsert() /hospital/bloodPressureInsert.json error : ', error); |
|
722 |
+ }); |
|
723 |
+ } |
|
724 |
+ |
|
725 |
+ //혈압 수정 |
|
726 |
+ const bloodPressureUpdate = () => { |
|
727 |
+ if (bloodPressureValidation() == false) { |
|
728 |
+ return; |
|
729 |
+ } |
|
730 |
+ |
|
731 |
+ bloodPressure['senior_id'] = targetSenior['senior_id']; |
|
732 |
+ bloodPressure['agent_id'] = defaultUserId; |
|
733 |
+ setBloodPressure({...bloodPressure}); |
|
734 |
+ |
|
735 |
+ fetch("/hospital/bloodPressureUpdate.json", { |
|
736 |
+ method: "POST", |
|
737 |
+ headers: { |
|
738 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
739 |
+ }, |
|
740 |
+ body: JSON.stringify(bloodPressure), |
|
741 |
+ }).then((response) => response.json()).then((data) => { |
|
742 |
+ console.log("혈압 수정 결과(건수) : ", data); |
|
743 |
+ if (data > 0) { |
|
744 |
+ setBloodPressureInit(); |
|
745 |
+ bloodPressureSelectList(); |
|
746 |
+ //closeModal2(); |
|
747 |
+ alert("수정완료"); |
|
748 |
+ } else { |
|
749 |
+ alert("수정에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
750 |
+ } |
|
751 |
+ }).catch((error) => { |
|
752 |
+ console.log('bloodPressureUpdate() /hospital/bloodPressureUpdate.json error : ', error); |
|
753 |
+ }); |
|
754 |
+ } |
|
755 |
+ |
|
756 |
+ //혈압 삭제 |
|
757 |
+ const bloodPressureDelete = () => { |
|
758 |
+ if (confirm('혈압 측정 정보를 삭제하시겠습니까?') == false) { |
|
759 |
+ return; |
|
760 |
+ } |
|
761 |
+ |
|
762 |
+ fetch("/hospital/bloodPressureDelete.json", { |
|
763 |
+ method: "POST", |
|
764 |
+ headers: { |
|
765 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
766 |
+ }, |
|
767 |
+ body: JSON.stringify(bloodPressure), |
|
768 |
+ }).then((response) => response.json()).then((data) => { |
|
769 |
+ console.log("혈압 삭제 결과(건수) : ", data); |
|
770 |
+ if (data > 0) { |
|
771 |
+ setBloodPressureInit(); |
|
772 |
+ bloodPressureSelectList(); |
|
773 |
+ //closeModal2(); |
|
774 |
+ alert("삭제완료"); |
|
775 |
+ } else { |
|
776 |
+ alert("삭제에 실패하였습니다. 관리자에게 문의바랍니다."); |
|
777 |
+ } |
|
778 |
+ }).catch((error) => { |
|
779 |
+ console.log('bloodPressureDelete() /hospital/bloodPressureDelete.json error : ', error); |
|
780 |
+ }); |
|
781 |
+ } |
|
782 |
+ |
|
783 |
+ //초기화 취소 |
|
784 |
+ const setBloodPressureInit = () => { |
|
785 |
+ setBloodPressure({...bloodPressureInit}); |
|
786 |
+ } |
|
787 |
+ |
|
788 |
+ //혈압 정보 |
|
789 |
+ const [bloodPressureList, setBloodPressureList] = React.useState({bloodPressureList: [], bloodPressureListCount:0, search: {currentPage: 1, perPage: 5}}); |
|
790 |
+ //혈압 목록 조회 |
|
791 |
+ const bloodPressureSelectList = (currentPage) => { |
|
792 |
+ bloodPressureList.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage; |
|
793 |
+ bloodPressureList.search['senior_id'] = targetSenior['senior_id']; |
|
794 |
+ setBloodPressureList({...bloodPressureList}); |
|
795 |
+ |
|
796 |
+ fetch("/hospital/bloodPressureSelectList.json", { |
|
797 |
+ method: "POST", |
|
798 |
+ headers: { |
|
799 |
+ 'Content-Type': 'application/json; charset=UTF-8' |
|
800 |
+ }, |
|
801 |
+ body: JSON.stringify(bloodPressureList.search), |
|
802 |
+ }).then((response) => response.json()).then((data) => { |
|
803 |
+ console.log("혈압 목록 조회 결과(건수) : ", data); |
|
804 |
+ data.search = bloodPressureList.search; |
|
805 |
+ setBloodPressureList(data); |
|
806 |
+ }).catch((error) => { |
|
807 |
+ console.log('bloodPressureSelectList() /hospital/bloodPressureSelectList.json error : ', error); |
|
808 |
+ }); |
|
809 |
+ } |
|
810 |
+ /****************** 혈압 (종료) ******************/ |
|
395 | 811 |
|
396 | 812 |
React.useEffect(() => { |
397 | 813 |
searching(); |
... | ... | @@ -519,9 +935,6 @@ |
519 | 935 |
<th>생년월일</th> |
520 | 936 |
<th>성별</th> |
521 | 937 |
<th>연락처</th> |
522 |
- <th>최고혈압</th> |
|
523 |
- <th>최저혈압</th> |
|
524 |
- <th>맥박수</th> |
|
525 | 938 |
<th>혈압관리</th> |
526 | 939 |
</tr> |
527 | 940 |
</thead> |
... | ... | @@ -534,9 +947,6 @@ |
534 | 947 |
<td data-label="생년월일">{item['user_birth']}</td> |
535 | 948 |
<td data-label="성별">{item['user_gender']}</td> |
536 | 949 |
<td data-label="연락처">{item['user_phonenumber']}</td> |
537 |
- <td>120</td> |
|
538 |
- <td>80</td> |
|
539 |
- <td>76</td> |
|
540 | 950 |
<td data-label="혈압관리"> |
541 | 951 |
<button className="btn-small gray-btn" onClick={() => openModal4(item)}>혈압관리</button> |
542 | 952 |
</td> |
... | ... | @@ -544,7 +954,7 @@ |
544 | 954 |
)})} |
545 | 955 |
{CommonUtil.isEmpty(senior.seniorList) ? |
546 | 956 |
<tr> |
547 |
- <td colSpan={10}>조회된 데이터가 없습니다</td> |
|
957 |
+ <td colSpan={7}>조회된 데이터가 없습니다</td> |
|
548 | 958 |
</tr> |
549 | 959 |
: null} |
550 | 960 |
</tbody> |
... | ... | @@ -949,6 +1359,7 @@ |
949 | 1359 |
: <> |
950 | 1360 |
<button className="btn-small gray-btn" onClick={setHospitalMedicalRecordInit}>수정취소</button> |
951 | 1361 |
<button className="btn-small red-btn" onClick={hospitalMedicalRecordUpdate}>수정</button> |
1362 |
+ <button className="btn-small red-btn" onClick={hospitalMedicalRecordDelete}>삭제</button> |
|
952 | 1363 |
</> |
953 | 1364 |
} |
954 | 1365 |
</div> |
... | ... | @@ -996,53 +1407,178 @@ |
996 | 1407 |
<div className="board-wrap"> |
997 | 1408 |
<table className="margin-bottom2 senior-insert "> |
998 | 1409 |
<tr> |
999 |
- <th>대상자명</th> |
|
1000 |
- <td className="flex-start"> |
|
1001 |
- <input type="text" placeholder="자동입력"/> |
|
1002 |
- </td> |
|
1003 |
- </tr> |
|
1004 |
- <tr> |
|
1005 | 1410 |
<th>측정 일자</th> |
1006 |
- <td className="flex-start"> |
|
1007 |
- <input type="text" placeholder="자동입력"/> |
|
1411 |
+ <td colSpan={5}> |
|
1412 |
+ <input type="date" value={ecg['ecg_reading_date']} |
|
1413 |
+ onChange={(e) => { |
|
1414 |
+ ecg['ecg_reading_date'] = e.target.value; |
|
1415 |
+ setEcg({...ecg}); |
|
1416 |
+ }} |
|
1417 |
+ ref={el => ecgRef.current['ecg_reading_date'] = el} |
|
1418 |
+ /> |
|
1008 | 1419 |
</td> |
1009 | 1420 |
</tr> |
1010 | 1421 |
<tr> |
1422 |
+ <th>판독 소견 종류</th> |
|
1423 |
+ <td colSpan={5}> |
|
1424 |
+ <input type="text" value={ecg['ecg_finding_type']} |
|
1425 |
+ onChange={(e) => { |
|
1426 |
+ ecg['ecg_finding_type'] = e.target.value; |
|
1427 |
+ setEcg({...ecg}); |
|
1428 |
+ }} |
|
1429 |
+ ref={el => ecgRef.current['ecg_finding_type'] = el} |
|
1430 |
+ /> |
|
1431 |
+ </td> |
|
1432 |
+ </tr> |
|
1433 |
+ <tr> |
|
1434 |
+ <th>판독 소견 내용</th> |
|
1435 |
+ <td colSpan={5}> |
|
1436 |
+ <textarea className="medicine" cols="30" rows="2" |
|
1437 |
+ value={ecg['ecg_finding_content']} |
|
1438 |
+ onChange={(e) => { |
|
1439 |
+ ecg['ecg_finding_content'] = e.target.value; |
|
1440 |
+ setEcg({...ecg}); |
|
1441 |
+ }} |
|
1442 |
+ ref={el => ecgRef.current['ecg_finding_content'] = el} |
|
1443 |
+ ></textarea> |
|
1444 |
+ </td> |
|
1445 |
+ </tr> |
|
1446 |
+ {ecg.isEdit == false |
|
1447 |
+ ? <tr> |
|
1011 | 1448 |
<th>측정 파일</th> |
1012 |
- <td className="flex-start"> |
|
1013 |
- <input type="file"></input> |
|
1449 |
+ <td colSpan={5}> |
|
1450 |
+ <CommonFile commonFileList={ecg['commonFileList']} multiple={false} accept={'.dat, .ecg'}/> |
|
1014 | 1451 |
</td> |
1015 | 1452 |
</tr> |
1016 |
- <tr> |
|
1017 |
- <th>등록자</th> |
|
1018 |
- <td className="flex-start"> |
|
1019 |
- <input type="text" placeholder="자동입력"/> |
|
1020 |
- </td> |
|
1021 |
- </tr> |
|
1453 |
+ : <> |
|
1454 |
+ <tr> |
|
1455 |
+ <th>서맥 횟수</th> |
|
1456 |
+ <td> |
|
1457 |
+ <input type="number" value={ecg['bradycardia_count']} |
|
1458 |
+ onChange={(e) => { |
|
1459 |
+ ecg['bradycardia_count'] = e.target.value; |
|
1460 |
+ setEcg({...ecg}); |
|
1461 |
+ }} |
|
1462 |
+ ref={el => ecgRef.current['bradycardia_count'] = el} |
|
1463 |
+ /> |
|
1464 |
+ </td> |
|
1465 |
+ <th>빈맥 횟수</th> |
|
1466 |
+ <td> |
|
1467 |
+ <input type="number" value={ecg['tachycardia_count']} |
|
1468 |
+ onChange={(e) => { |
|
1469 |
+ ecg['tachycardia_count'] = e.target.value; |
|
1470 |
+ setEcg({...ecg}); |
|
1471 |
+ }} |
|
1472 |
+ ref={el => ecgRef.current['tachycardia_count'] = el} |
|
1473 |
+ /> |
|
1474 |
+ </td> |
|
1475 |
+ <th>이상 심박수</th> |
|
1476 |
+ <td> |
|
1477 |
+ <input type="number" value={ecg['abnormal_heart_rate']} |
|
1478 |
+ onChange={(e) => { |
|
1479 |
+ ecg['abnormal_heart_rate'] = e.target.value; |
|
1480 |
+ setEcg({...ecg}); |
|
1481 |
+ }} |
|
1482 |
+ ref={el => ecgRef.current['abnormal_heart_rate'] = el} |
|
1483 |
+ /> |
|
1484 |
+ </td> |
|
1485 |
+ </tr> |
|
1486 |
+ <tr> |
|
1487 |
+ <th>최대 심박수</th> |
|
1488 |
+ <td> |
|
1489 |
+ <input type="number" value={ecg['max_heart_rate']} |
|
1490 |
+ onChange={(e) => { |
|
1491 |
+ ecg['max_heart_rate'] = e.target.value; |
|
1492 |
+ setEcg({...ecg}); |
|
1493 |
+ }} |
|
1494 |
+ ref={el => ecgRef.current['max_heart_rate'] = el} |
|
1495 |
+ /> |
|
1496 |
+ </td> |
|
1497 |
+ <th>최소 심박수</th> |
|
1498 |
+ <td> |
|
1499 |
+ <input type="number" value={ecg['min_heart_rate']} |
|
1500 |
+ onChange={(e) => { |
|
1501 |
+ ecg['min_heart_rate'] = e.target.value; |
|
1502 |
+ setEcg({...ecg}); |
|
1503 |
+ }} |
|
1504 |
+ ref={el => ecgRef.current['min_heart_rate'] = el} |
|
1505 |
+ /> |
|
1506 |
+ </td> |
|
1507 |
+ <th>평균 심박수</th> |
|
1508 |
+ <td> |
|
1509 |
+ <input type="number" value={ecg['average_heart_rate']} |
|
1510 |
+ onChange={(e) => { |
|
1511 |
+ ecg['average_heart_rate'] = e.target.value; |
|
1512 |
+ setEcg({...ecg}); |
|
1513 |
+ }} |
|
1514 |
+ ref={el => ecgRef.current['average_heart_rate'] = el} |
|
1515 |
+ /> |
|
1516 |
+ </td> |
|
1517 |
+ </tr> |
|
1518 |
+ <tr> |
|
1519 |
+ <th>최대 R-R</th> |
|
1520 |
+ <td> |
|
1521 |
+ <input type="number" value={ecg['max_rr']} |
|
1522 |
+ onChange={(e) => { |
|
1523 |
+ ecg['max_rr'] = e.target.value; |
|
1524 |
+ setEcg({...ecg}); |
|
1525 |
+ }} |
|
1526 |
+ ref={el => ecgRef.current['max_rr'] = el} |
|
1527 |
+ /> |
|
1528 |
+ </td> |
|
1529 |
+ <th>최소 R-R</th> |
|
1530 |
+ <td> |
|
1531 |
+ <input type="number" value={ecg['min_rr']} |
|
1532 |
+ onChange={(e) => { |
|
1533 |
+ ecg['min_rr'] = e.target.value; |
|
1534 |
+ setEcg({...ecg}); |
|
1535 |
+ }} |
|
1536 |
+ ref={el => ecgRef.current['min_rr'] = el} |
|
1537 |
+ /> |
|
1538 |
+ </td> |
|
1539 |
+ <th>평균 R-R</th> |
|
1540 |
+ <td> |
|
1541 |
+ <input type="number" value={ecg['average_rr']} |
|
1542 |
+ onChange={(e) => { |
|
1543 |
+ ecg['average_rr'] = e.target.value; |
|
1544 |
+ setEcg({...ecg}); |
|
1545 |
+ }} |
|
1546 |
+ ref={el => ecgRef.current['average_rr'] = el} |
|
1547 |
+ /> |
|
1548 |
+ </td> |
|
1549 |
+ </tr> |
|
1550 |
+ </>} |
|
1022 | 1551 |
</table> |
1023 | 1552 |
<div className="btn-wrap flex-center margin-bottom5"> |
1024 |
- <button className="btn-small red-btn" onClick={closeModal3}>저장</button> |
|
1553 |
+ {CommonUtil.isEmpty(ecg['ecg_record_idx']) |
|
1554 |
+ ? <button className="btn-small red-btn" onClick={ecgInsert}>등록</button> |
|
1555 |
+ : <> |
|
1556 |
+ <button className="btn-small gray-btn" onClick={setEcgInit}>수정취소</button> |
|
1557 |
+ <button className="btn-small red-btn" onClick={ecgUpdate}>수정</button> |
|
1558 |
+ <button className="btn-small red-btn" onClick={ecgDelete}>삭제</button> |
|
1559 |
+ </> |
|
1560 |
+ } |
|
1025 | 1561 |
</div> |
1026 | 1562 |
<div> |
1027 | 1563 |
<table className="caregiver-user senior-table"> |
1028 | 1564 |
<thead> |
1029 | 1565 |
<tr> |
1030 | 1566 |
<th>No</th> |
1031 |
- <th>측정 일자</th> |
|
1032 | 1567 |
<th>소견 작성 일자</th> |
1568 |
+ <th>판독 소견 종류</th> |
|
1033 | 1569 |
<th>소견 작성자</th> |
1034 | 1570 |
</tr> |
1035 | 1571 |
</thead> |
1036 | 1572 |
<tbody> |
1037 |
- {senior.seniorList.map((item, idx) => { return ( |
|
1038 |
- <tr key={idx}> |
|
1039 |
- <td data-label="No">{senior.seniorListCount - idx - (senior.search.currentPage - 1) * senior.search.perPage}</td> |
|
1040 |
- <td data-label="소속기관명">{item['agency_name']}</td> |
|
1041 |
- <td data-label="이름">{item['user_name']}</td> |
|
1042 |
- <td data-label="생년월일">{item['user_birth']}</td> |
|
1573 |
+ {ecgList.ecgList.map((item, idx) => { return ( |
|
1574 |
+ <tr key={idx} onClick={() => {item.isEdit = false; setEcg(item);}}> |
|
1575 |
+ <td data-label="No">{ecgList.ecgListCount - idx - (ecgList.search.currentPage - 1) * ecgList.search.perPage}</td> |
|
1576 |
+ <td data-label="소견 작성 일자">{item['ecg_reading_date']}</td> |
|
1577 |
+ <td data-label="판독 소견 종류">{item['ecg_finding_type']}</td> |
|
1578 |
+ <td data-label="소견 작성자">{item['insert_user_name']}</td> |
|
1043 | 1579 |
</tr> |
1044 | 1580 |
)})} |
1045 |
- {CommonUtil.isEmpty(senior.seniorList) ? |
|
1581 |
+ {CommonUtil.isEmpty(ecgList.ecgList) ? |
|
1046 | 1582 |
<tr> |
1047 | 1583 |
<td colSpan={4}>조회된 데이터가 없습니다</td> |
1048 | 1584 |
</tr> |
... | ... | @@ -1050,11 +1586,11 @@ |
1050 | 1586 |
</tbody> |
1051 | 1587 |
</table> |
1052 | 1588 |
<Pagination |
1053 |
- currentPage={senior.search.currentPage} |
|
1054 |
- perPage={senior.search.perPage} |
|
1055 |
- totalCount={senior.seniorListCount} |
|
1589 |
+ currentPage={ecgList.search.currentPage} |
|
1590 |
+ perPage={ecgList.search.perPage} |
|
1591 |
+ totalCount={ecgList.ecgListCount} |
|
1056 | 1592 |
maxRange={5} |
1057 |
- click={seniorSelectList} |
|
1593 |
+ click={ecgSelectList} |
|
1058 | 1594 |
/> |
1059 | 1595 |
</div> |
1060 | 1596 |
</div> |
... | ... | @@ -1065,45 +1601,70 @@ |
1065 | 1601 |
<div className="board-wrap"> |
1066 | 1602 |
<table className="margin-bottom2 senior-insert "> |
1067 | 1603 |
<tr> |
1068 |
- <th>대상자명</th> |
|
1069 |
- <td className="flex-start"> |
|
1070 |
- <input type="text" placeholder="자동입력"/> |
|
1071 |
- </td> |
|
1072 |
- </tr> |
|
1073 |
- <tr> |
|
1074 | 1604 |
<th>측정일자</th> |
1075 |
- <td className="flex-start"> |
|
1076 |
- <input type="text" placeholder="자동입력"/> |
|
1605 |
+ <td> |
|
1606 |
+ <input type="date" value={bloodPressure['blood_pressure_record_date']} |
|
1607 |
+ onChange={(e) => { |
|
1608 |
+ bloodPressure['blood_pressure_record_date'] = e.target.value; |
|
1609 |
+ setBloodPressure({...bloodPressure}); |
|
1610 |
+ }} |
|
1611 |
+ ref={el => bloodPressureRef.current['blood_pressure_record_date'] = el} |
|
1612 |
+ /> |
|
1077 | 1613 |
</td> |
1078 | 1614 |
</tr> |
1079 | 1615 |
<tr> |
1080 | 1616 |
<th>최고혈압</th> |
1081 |
- <td className="flex-start"> |
|
1082 |
- <input type="text" /> |
|
1083 |
- </td> |
|
1617 |
+ <td> |
|
1618 |
+ <input type="number" value={bloodPressure['max_blood_pressure']} |
|
1619 |
+ onChange={(e) => { |
|
1620 |
+ bloodPressure['max_blood_pressure'] = e.target.value; |
|
1621 |
+ setBloodPressure({...bloodPressure}); |
|
1622 |
+ }} |
|
1623 |
+ ref={el => bloodPressureRef.current['max_blood_pressure'] = el} |
|
1624 |
+ /> |
|
1625 |
+ </td> |
|
1084 | 1626 |
</tr> |
1085 | 1627 |
<tr> |
1086 | 1628 |
<th>최저혈압</th> |
1087 |
- <td className="flex-start"> |
|
1088 |
- <input type="text" /> |
|
1089 |
- </td> |
|
1629 |
+ <td> |
|
1630 |
+ <input type="number" value={bloodPressure['min_blood_pressure']} |
|
1631 |
+ onChange={(e) => { |
|
1632 |
+ bloodPressure['min_blood_pressure'] = e.target.value; |
|
1633 |
+ setBloodPressure({...bloodPressure}); |
|
1634 |
+ }} |
|
1635 |
+ ref={el => bloodPressureRef.current['min_blood_pressure'] = el} |
|
1636 |
+ /> |
|
1637 |
+ </td> |
|
1090 | 1638 |
</tr> |
1091 | 1639 |
<tr> |
1092 | 1640 |
<th>맥박수</th> |
1093 |
- <td className="flex-start"> |
|
1094 |
- <input type="text" /> |
|
1095 |
- </td> |
|
1641 |
+ <td> |
|
1642 |
+ <input type="number" value={bloodPressure['pulse_rate']} |
|
1643 |
+ onChange={(e) => { |
|
1644 |
+ bloodPressure['pulse_rate'] = e.target.value; |
|
1645 |
+ setBloodPressure({...bloodPressure}); |
|
1646 |
+ }} |
|
1647 |
+ ref={el => bloodPressureRef.current['pulse_rate'] = el} |
|
1648 |
+ /> |
|
1649 |
+ </td> |
|
1096 | 1650 |
</tr> |
1097 | 1651 |
</table> |
1098 | 1652 |
<div className="btn-wrap flex-center margin-bottom5"> |
1099 |
- <button className="btn-small red-btn" onClick={closeModal4}>저장</button> |
|
1653 |
+ {CommonUtil.isEmpty(bloodPressure['blood_pressure_record_idx']) |
|
1654 |
+ ? <button className="btn-small red-btn" onClick={bloodPressureInsert}>등록</button> |
|
1655 |
+ : <> |
|
1656 |
+ <button className="btn-small gray-btn" onClick={setBloodPressureInit}>수정취소</button> |
|
1657 |
+ <button className="btn-small red-btn" onClick={bloodPressureUpdate}>수정</button> |
|
1658 |
+ <button className="btn-small red-btn" onClick={bloodPressureDelete}>삭제</button> |
|
1659 |
+ </> |
|
1660 |
+ } |
|
1100 | 1661 |
</div> |
1101 | 1662 |
<div> |
1102 | 1663 |
<table className="caregiver-user senior-insert senior-table"> |
1103 | 1664 |
<thead> |
1104 | 1665 |
<tr> |
1105 | 1666 |
<th>No</th> |
1106 |
- <th>측정 일자</th> |
|
1667 |
+ <th>기록 작성일</th> |
|
1107 | 1668 |
<th>최고 혈압</th> |
1108 | 1669 |
<th>최저 혈압</th> |
1109 | 1670 |
<th>맥박수</th> |
... | ... | @@ -1111,28 +1672,29 @@ |
1111 | 1672 |
</tr> |
1112 | 1673 |
</thead> |
1113 | 1674 |
<tbody> |
1114 |
- {senior.seniorList.map((item, idx) => { return ( |
|
1115 |
- <tr key={idx}> |
|
1116 |
- <td data-label="No">{senior.seniorListCount - idx - (senior.search.currentPage - 1) * senior.search.perPage}</td> |
|
1117 |
- <td data-label="소속기관명">{item['agency_name']}</td> |
|
1118 |
- <td data-label="이름">{item['user_name']}</td> |
|
1119 |
- <td data-label="생년월일">{item['user_birth']}</td> |
|
1120 |
- <td data-label="성별">{item['user_gender']}</td> |
|
1675 |
+ {bloodPressureList.bloodPressureList.map((item, idx) => { return ( |
|
1676 |
+ <tr key={idx} onClick={() => {setBloodPressure(item);}}> |
|
1677 |
+ <td data-label="No">{bloodPressureList.bloodPressureListCount - idx - (bloodPressureList.search.currentPage - 1) * bloodPressureList.search.perPage}</td> |
|
1678 |
+ <td data-label="기록 작성일">{item['blood_pressure_record_date']}</td> |
|
1679 |
+ <td data-label="최고 혈압">{item['max_blood_pressure']}</td> |
|
1680 |
+ <td data-label="최저 혈압">{item['min_blood_pressure']}</td> |
|
1681 |
+ <td data-label="맥박수">{item['pulse_rate']}</td> |
|
1682 |
+ <td data-label="기록 작성자">{item['insert_user_name']}</td> |
|
1121 | 1683 |
</tr> |
1122 | 1684 |
)})} |
1123 |
- {CommonUtil.isEmpty(senior.seniorList) ? |
|
1685 |
+ {CommonUtil.isEmpty(bloodPressureList.bloodPressureList) ? |
|
1124 | 1686 |
<tr> |
1125 |
- <td colSpan={5}>조회된 데이터가 없습니다</td> |
|
1687 |
+ <td colSpan={6}>조회된 데이터가 없습니다</td> |
|
1126 | 1688 |
</tr> |
1127 | 1689 |
: null} |
1128 | 1690 |
</tbody> |
1129 | 1691 |
</table> |
1130 | 1692 |
<Pagination |
1131 |
- currentPage={senior.search.currentPage} |
|
1132 |
- perPage={senior.search.perPage} |
|
1133 |
- totalCount={senior.seniorListCount} |
|
1693 |
+ currentPage={bloodPressureList.search.currentPage} |
|
1694 |
+ perPage={bloodPressureList.search.perPage} |
|
1695 |
+ totalCount={bloodPressureList.bloodPressureListCount} |
|
1134 | 1696 |
maxRange={5} |
1135 |
- click={seniorSelectList} |
|
1697 |
+ click={bloodPressureSelectList} |
|
1136 | 1698 |
/> |
1137 | 1699 |
</div> |
1138 | 1700 |
</div> |
--- server/modules/web/Server.js
+++ server/modules/web/Server.js
... | ... | @@ -109,6 +109,24 @@ |
109 | 109 |
return `${request.params['0']}.json`; |
110 | 110 |
} |
111 | 111 |
})); |
112 |
+ |
|
113 |
+ |
|
114 |
+/** |
|
115 |
+ * @author : 최정우 |
|
116 |
+ * @since : 2023.03.18 |
|
117 |
+ * @dscription : REST API 서버에 File 요청 보내기(Proxy) |
|
118 |
+ * express-http-proxy 라이브러리에서 Request Body 구문해석을 못하도록 강제로 막음 (parseReqBody: false) |
|
119 |
+ * => 이유 : 구문해석 후, express-http-proxy가 Body의 내용을 변형시키는 듯 함. |
|
120 |
+ * 그래서, API 서버에 제대로된 Body를 전달하지 못 함 |
|
121 |
+ */ |
|
122 |
+webServer.use('*.file', expressProxy(API_SERVER_HOST, { |
|
123 |
+ parseReqBody: false, |
|
124 |
+ proxyReqPathResolver: function (request) { |
|
125 |
+ console.log('request : ', request.url, request.params[0]); |
|
126 |
+ return `${request.params['0']}.file`; |
|
127 |
+ } |
|
128 |
+})); |
|
129 |
+ |
|
112 | 130 |
|
113 | 131 |
/** |
114 | 132 |
* @author : 최정우 |
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?