박권수

feat. qrcode 생성

This diff is collapsed. Click to expand it.
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
14 "highcharts": "^9.2.0", 14 "highcharts": "^9.2.0",
15 "highcharts-react-official": "^3.0.0", 15 "highcharts-react-official": "^3.0.0",
16 "moment": "^2.29.1", 16 "moment": "^2.29.1",
17 + "qrcode": "^1.4.4",
17 "react": "^17.0.2", 18 "react": "^17.0.2",
18 "react-dom": "^17.0.2", 19 "react-dom": "^17.0.2",
19 "react-router-dom": "^5.2.0", 20 "react-router-dom": "^5.2.0",
...@@ -52,6 +53,7 @@ ...@@ -52,6 +53,7 @@
52 ] 53 ]
53 }, 54 },
54 "devDependencies": { 55 "devDependencies": {
56 + "@types/qrcode": "^1.4.1",
55 "@types/react-router-dom": "^5.1.8", 57 "@types/react-router-dom": "^5.1.8",
56 "@types/styled-components": "^5.1.12", 58 "@types/styled-components": "^5.1.12",
57 "@types/validator": "^13.6.3", 59 "@types/validator": "^13.6.3",
......
...@@ -9,6 +9,12 @@ export const token = atom({ ...@@ -9,6 +9,12 @@ export const token = atom({
9 effects_UNSTABLE : [persistAtom], 9 effects_UNSTABLE : [persistAtom],
10 }); 10 });
11 11
12 +export const userId = atom({
13 + key : 'userId',
14 + default : null,
15 + effects_UNSTABLE : [persistAtom],
16 +});
17 +
12 export const userTypeCd = atom({ 18 export const userTypeCd = atom({
13 key : 'userTypeCd', 19 key : 'userTypeCd',
14 default : 'NORMAL', 20 default : 'NORMAL',
......
...@@ -23,6 +23,7 @@ const LoginContainer = (props : LoginProps) => { ...@@ -23,6 +23,7 @@ const LoginContainer = (props : LoginProps) => {
23 }); 23 });
24 24
25 const [token, setToken] = useRecoilState(recoilUtil.token); 25 const [token, setToken] = useRecoilState(recoilUtil.token);
26 + const [userId, setUserId] = useRecoilState(recoilUtil.userId);
26 const [userTypeCd, setUserTypeCd] = useRecoilState(recoilUtil.userTypeCd); 27 const [userTypeCd, setUserTypeCd] = useRecoilState(recoilUtil.userTypeCd);
27 28
28 29
...@@ -58,12 +59,13 @@ const LoginContainer = (props : LoginProps) => { ...@@ -58,12 +59,13 @@ const LoginContainer = (props : LoginProps) => {
58 const result : any = await authApi.login(loginForm); 59 const result : any = await authApi.login(loginForm);
59 if(result.statusText === 'OK' && result.data.userTypeCd !== 'NORMAL') { 60 if(result.statusText === 'OK' && result.data.userTypeCd !== 'NORMAL') {
60 setToken(result.data.token); 61 setToken(result.data.token);
62 + setUserId(loginForm.userId);
61 setUserTypeCd(result.data.userTypeCd); 63 setUserTypeCd(result.data.userTypeCd);
62 Alert.onSuccess('로그인 성공, 메인 화면으로 이동합니다.', () => props.history.push('/')); 64 Alert.onSuccess('로그인 성공, 메인 화면으로 이동합니다.', () => props.history.push('/'));
63 } else if(result.data.userTypeCd === 'NORMAL') { 65 } else if(result.data.userTypeCd === 'NORMAL') {
64 Alert.onError('권한이 없는 유저입니다.', () => props.history.push('/')); 66 Alert.onError('권한이 없는 유저입니다.', () => props.history.push('/'));
65 } 67 }
66 - } catch(e) { 68 + } catch(e : any) {
67 Alert.onError(e.response.data.error, () => null); 69 Alert.onError(e.response.data.error, () => null);
68 } 70 }
69 71
......
...@@ -10,6 +10,8 @@ import * as Alert from '../../../util/alertMessage'; ...@@ -10,6 +10,8 @@ import * as Alert from '../../../util/alertMessage';
10 10
11 import { doctorApi, medicineApi } from '../../../api'; 11 import { doctorApi, medicineApi } from '../../../api';
12 12
13 +import QRCode from 'qrcode';
14 +
13 15
14 //toDo : Generate QR Code By Medicine Id 16 //toDo : Generate QR Code By Medicine Id
15 17
...@@ -18,6 +20,7 @@ type DoctorMenuProps = RouteComponentProps ...@@ -18,6 +20,7 @@ type DoctorMenuProps = RouteComponentProps
18 const DoctorMenuContainer = (props : DoctorMenuProps) => { 20 const DoctorMenuContainer = (props : DoctorMenuProps) => {
19 21
20 const token = useRecoilValue(recoilUtil.token); 22 const token = useRecoilValue(recoilUtil.token);
23 + const userId = useRecoilValue(recoilUtil.userId);
21 const [loading, setLoading] = useRecoilState(recoilUtil.loading); 24 const [loading, setLoading] = useRecoilState(recoilUtil.loading);
22 25
23 const [doctorInfo, setDoctorInfo] = useState<any>({ 26 const [doctorInfo, setDoctorInfo] = useState<any>({
...@@ -52,9 +55,13 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { ...@@ -52,9 +55,13 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
52 const [newPatientSearchResult, setNewPatientSearchResult] = useState<any | null>(null); 55 const [newPatientSearchResult, setNewPatientSearchResult] = useState<any | null>(null);
53 56
54 const [prescribeModal, setPrescribeModal] = useState<boolean>(false); 57 const [prescribeModal, setPrescribeModal] = useState<boolean>(false);
58 + const [prescribeModalStep, setPrescribeModalStep] = useState<number>(1);
55 const [searchMedicineKeyword, setSearchMedicineKeyword] = useState<string>(''); 59 const [searchMedicineKeyword, setSearchMedicineKeyword] = useState<string>('');
56 const [medicineList, setMedicineList] = useState<any>([]); 60 const [medicineList, setMedicineList] = useState<any>([]);
57 const [prescribeMedicine, setPrescribeMedicine] = useState<any>(null); 61 const [prescribeMedicine, setPrescribeMedicine] = useState<any>(null);
62 + const [dosage, setDosage] = useState<string>('1');
63 +
64 + const [qrcodeUrl, setQrcodeUrl] = useState<string | null>(null);
58 65
59 66
60 const fetchData = async() => { 67 const fetchData = async() => {
...@@ -213,9 +220,11 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { ...@@ -213,9 +220,11 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
213 setEditModal(false); 220 setEditModal(false);
214 setEditPatientInfo(''); 221 setEditPatientInfo('');
215 setPrescribeModal(false); 222 setPrescribeModal(false);
223 + setPrescribeModalStep(1);
216 setSearchMedicineKeyword(''); 224 setSearchMedicineKeyword('');
217 setMedicineList([]); 225 setMedicineList([]);
218 setPrescribeMedicine(null); 226 setPrescribeMedicine(null);
227 + setDosage('1');
219 }; 228 };
220 229
221 const onGoBottleDetail = (bottleId : number) => { 230 const onGoBottleDetail = (bottleId : number) => {
...@@ -233,7 +242,6 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { ...@@ -233,7 +242,6 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
233 setLoading(true); 242 setLoading(true);
234 const res = await medicineApi.searchMedicine(token, searchMedicineKeyword); 243 const res = await medicineApi.searchMedicine(token, searchMedicineKeyword);
235 if(res.statusText === 'OK') { 244 if(res.statusText === 'OK') {
236 - console.log(res.data.medicineList)
237 setMedicineList(res.data.medicineList); 245 setMedicineList(res.data.medicineList);
238 } 246 }
239 setLoading(false); 247 setLoading(false);
...@@ -242,9 +250,32 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { ...@@ -242,9 +250,32 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
242 } 250 }
243 }; 251 };
244 252
253 + const onSetDosage = (e : React.ChangeEvent<HTMLInputElement>) => {
254 + setDosage(e.target.value);
255 + };
256 +
257 + const onSetNextStepPrescribe = () => {
258 + if(prescribeMedicine) setPrescribeModalStep(prescribeModalStep + 1);
259 + else Alert.onWarning('먼저 처방할 약을 선택해야 합니다.', () => null);
260 + };
261 +
262 + const onSetPrevStepPrescribe = () => {
263 + if(prescribeModalStep > 1) setPrescribeModalStep(prescribeModalStep - 1);
264 + };
265 +
245 const onPrescribeSubmit = async() => { 266 const onPrescribeSubmit = async() => {
246 - //toDo : 처방해서, QR코드 생성 267 + Alert.onCheck(`${prescribeMedicine.name}(일 복용량:${dosage})\n을 처방하시겠습니까?`, async () => {
247 - Alert.onWarning('작업 중입니다.', () => null); 268 + setQrcodeUrl(await QRCode.toDataURL(`${prescribeMedicine.name}/${prescribeMedicine.medicineId}/${dosage}/${userId}`, {
269 + type : "image/png",
270 + color : {dark : '#337DFF', light : '#FFF'},
271 + }));
272 + Alert.onSuccess('처방 정보가 생성 되었습니다.', () => onSetNextStepPrescribe());
273 + }, () => null);
274 + };
275 +
276 + const onPrintQrcode = async() => {
277 + //toDo : QR코드 출력
278 + Alert.onWarning('준비 중입니다.', () => null);
248 }; 279 };
249 280
250 const onPrescribeCancel = () => { 281 const onPrescribeCancel = () => {
...@@ -298,14 +329,21 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => { ...@@ -298,14 +329,21 @@ const DoctorMenuContainer = (props : DoctorMenuProps) => {
298 onCloseModal = {onCloseModal} 329 onCloseModal = {onCloseModal}
299 330
300 prescribeModal = {prescribeModal} 331 prescribeModal = {prescribeModal}
332 + prescribeModalStep = {prescribeModalStep}
333 + onSetNextStepPrescribe = {onSetNextStepPrescribe}
334 + onSetPrevStepPrescribe = {onSetPrevStepPrescribe}
301 setPrescribeModal = {setPrescribeModal} 335 setPrescribeModal = {setPrescribeModal}
302 searchMedicineKeyword = {searchMedicineKeyword} 336 searchMedicineKeyword = {searchMedicineKeyword}
303 onSetSearchMedicineKeyword = {onSetSearchMedicineKeyword} 337 onSetSearchMedicineKeyword = {onSetSearchMedicineKeyword}
304 medicineList = {medicineList} 338 medicineList = {medicineList}
305 searchMedicine = {searchMedicine} 339 searchMedicine = {searchMedicine}
306 prescribeMedicine = {prescribeMedicine} 340 prescribeMedicine = {prescribeMedicine}
341 + dosage = {dosage}
342 + onSetDosage = {onSetDosage}
343 + qrcodeUrl = {qrcodeUrl}
307 setPrescribeMedicine = {setPrescribeMedicine} 344 setPrescribeMedicine = {setPrescribeMedicine}
308 onPrescribeSubmit = {onPrescribeSubmit} 345 onPrescribeSubmit = {onPrescribeSubmit}
346 + onPrintQrcode = {onPrintQrcode}
309 onPrescribeCancel = {onPrescribeCancel} 347 onPrescribeCancel = {onPrescribeCancel}
310 348
311 newPatientSearchResult = {newPatientSearchResult} 349 newPatientSearchResult = {newPatientSearchResult}
......
...@@ -48,6 +48,10 @@ interface DoctorMenuProps { ...@@ -48,6 +48,10 @@ interface DoctorMenuProps {
48 48
49 prescribeModal : boolean; 49 prescribeModal : boolean;
50 setPrescribeModal : any; 50 setPrescribeModal : any;
51 + prescribeModalStep : number;
52 + onSetNextStepPrescribe : () => void;
53 + onSetPrevStepPrescribe : () => void;
54 +
51 searchMedicineKeyword : string; 55 searchMedicineKeyword : string;
52 onSetSearchMedicineKeyword : React.ChangeEventHandler<HTMLInputElement>; 56 onSetSearchMedicineKeyword : React.ChangeEventHandler<HTMLInputElement>;
53 57
...@@ -57,7 +61,13 @@ interface DoctorMenuProps { ...@@ -57,7 +61,13 @@ interface DoctorMenuProps {
57 prescribeMedicine : any; 61 prescribeMedicine : any;
58 setPrescribeMedicine : (arg0 : any) => void; 62 setPrescribeMedicine : (arg0 : any) => void;
59 63
64 + dosage : string;
65 + onSetDosage : React.ChangeEventHandler<HTMLInputElement>;
66 +
67 + qrcodeUrl : string | null;
68 +
60 onPrescribeSubmit : () => void; 69 onPrescribeSubmit : () => void;
70 + onPrintQrcode : () => void;
61 onPrescribeCancel : () => void; 71 onPrescribeCancel : () => void;
62 } 72 }
63 73
...@@ -189,53 +199,105 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => { ...@@ -189,53 +199,105 @@ const DoctorMenuPresenter = (props : DoctorMenuProps) => {
189 <styled.ModalContentWrapper> 199 <styled.ModalContentWrapper>
190 <styled.ModalContent> 200 <styled.ModalContent>
191 <styled.MedicineSearchTitle> 201 <styled.MedicineSearchTitle>
192 - 약 검색 202 + {
203 + props.prescribeModalStep === 1 ?
204 + '약 검색' :
205 + props.prescribeModalStep === 2 ?
206 + '복용량 입력' :
207 + '처방 정보 QR코드'
208 + }
193 </styled.MedicineSearchTitle> 209 </styled.MedicineSearchTitle>
194 - <styled.MedicineSearchInputWrapper>
195 - <styled.MedicineSearchInput
196 - placeholder = '증상, 또는 약 이름을 검색하세요.'
197 - onChange = {props.onSetSearchMedicineKeyword}
198 - value = {props.searchMedicineKeyword}
199 - />
200 - <styled.MedicineSearchButton
201 - onClick = {props.searchMedicine}
202 - >
203 - <styled.MedicineSearchButtonImg src = {lensImg}/>
204 - </styled.MedicineSearchButton>
205 - </styled.MedicineSearchInputWrapper>
206 - <styled.MedicineSearchResultWrapper>
207 { 210 {
208 - props.medicineList.length ? 211 + props.prescribeModalStep === 1 ?
209 - props.medicineList.map((medicine : any) => { 212 + <>
210 - return ( 213 + <styled.MedicineSearchInputWrapper>
211 - <styled.MedicineSearchResultEach 214 + <styled.MedicineSearchInput
212 - key = {medicine.medicineId} 215 + placeholder = '증상, 또는 약 이름을 검색하세요.'
213 - onClick = {() => props.setPrescribeMedicine(medicine)} 216 + onChange = {props.onSetSearchMedicineKeyword}
214 - > 217 + value = {props.searchMedicineKeyword}
215 - <styled.MedicineSearchResultEachInfo> 218 + />
216 - {medicine.name} 219 + <styled.MedicineSearchButton
217 - </styled.MedicineSearchResultEachInfo> 220 + onClick = {props.searchMedicine}
218 - <styled.MedicineSearchButtonImg 221 + >
219 - src = { 222 + <styled.MedicineSearchButtonImg src = {lensImg}/>
220 - props.prescribeMedicine && props.prescribeMedicine.medicineId === medicine.medicineId ? 223 + </styled.MedicineSearchButton>
221 - check : uncheck 224 + </styled.MedicineSearchInputWrapper>
222 - } 225 + <styled.MedicineSearchResultWrapper>
223 - /> 226 + {
224 - </styled.MedicineSearchResultEach> 227 + props.medicineList.length ?
225 - ) 228 + props.medicineList.map((medicine : any) => {
226 - }) : 229 + return (
227 - <styled.NothingWrapper style = {{fontSize : 13,}}> 230 + <styled.MedicineSearchResultEach
228 - 🤔검색 결과가 없습니다. 231 + key = {medicine.medicineId}
229 - </styled.NothingWrapper> 232 + onClick = {() => props.setPrescribeMedicine(
233 + props.prescribeMedicine && props.prescribeMedicine.medicineId === medicine.medicineId ?
234 + null : medicine
235 + )}
236 + >
237 + <styled.MedicineSearchResultEachInfo>
238 + {medicine.name}
239 + </styled.MedicineSearchResultEachInfo>
240 + <styled.MedicineSearchButtonImg
241 + src = {
242 + props.prescribeMedicine && props.prescribeMedicine.medicineId === medicine.medicineId ?
243 + check : uncheck
244 + }
245 + />
246 + </styled.MedicineSearchResultEach>
247 + )
248 + }) :
249 + <styled.NothingWrapper style = {{fontSize : 13,}}>
250 + 🤔검색 결과가 없습니다.
251 + </styled.NothingWrapper>
252 + }
253 + </styled.MedicineSearchResultWrapper>
254 + </>
255 + :
256 + props.prescribeModalStep === 2 ?
257 + <styled.MedicineDosageSetWrapper>
258 + <styled.MedicineDosageInfo>
259 + *하루 복용량을 입력하세요.
260 + </styled.MedicineDosageInfo>
261 + <styled.MedicineDosageInput
262 + value = {props.dosage}
263 + onChange = {props.onSetDosage}
264 + />
265 + </styled.MedicineDosageSetWrapper>
266 + :
267 + <styled.MedicineQRCodeWrapper>
268 + <styled.MedicineQRCodeInfo>
269 + *어플리케이션에서 QR코드를 스캔하면 약병에 약이 등록됩니다.
270 + </styled.MedicineQRCodeInfo>
271 + {
272 + props.qrcodeUrl ?
273 + <styled.MedicineQRCode src = {props.qrcodeUrl}/> : null
274 + }
275 + </styled.MedicineQRCodeWrapper>
230 } 276 }
231 - </styled.MedicineSearchResultWrapper>
232 <styled.MedicinePrescribeButtonWrapper> 277 <styled.MedicinePrescribeButtonWrapper>
233 - <styled.MedicinePrescribeButton 278 + {
234 - isClose = {false} 279 + props.prescribeModalStep === 1 ?
235 - onClick = {props.onPrescribeSubmit} 280 + <styled.MedicinePrescribeButton
236 - > 281 + isClose = {false}
237 - 처방 282 + onClick = {props.onSetNextStepPrescribe}
238 - </styled.MedicinePrescribeButton> 283 + >
284 + 다음 단계
285 + </styled.MedicinePrescribeButton> :
286 + props.prescribeModalStep === 2 ?
287 + <styled.MedicinePrescribeButton
288 + isClose = {false}
289 + onClick = {props.onPrescribeSubmit}
290 + >
291 + 처방
292 + </styled.MedicinePrescribeButton>
293 + :
294 + <styled.MedicinePrescribeButton
295 + isClose = {false}
296 + onClick = {props.onPrintQrcode}
297 + >
298 + 출력
299 + </styled.MedicinePrescribeButton>
300 + }
239 <styled.MedicinePrescribeButton 301 <styled.MedicinePrescribeButton
240 isClose = {true} 302 isClose = {true}
241 onClick = {props.onPrescribeCancel} 303 onClick = {props.onPrescribeCancel}
......
...@@ -436,6 +436,7 @@ export const MedicineSearchButtonImg = styled.img ` ...@@ -436,6 +436,7 @@ export const MedicineSearchButtonImg = styled.img `
436 height : 15px; 436 height : 15px;
437 width : 15px; 437 width : 15px;
438 438
439 + transition : .25s all;
439 `; 440 `;
440 441
441 export const MedicineSearchResultWrapper = styled.div ` 442 export const MedicineSearchResultWrapper = styled.div `
...@@ -499,6 +500,92 @@ export const MedicineSelectButtonImg = styled.img ` ...@@ -499,6 +500,92 @@ export const MedicineSelectButtonImg = styled.img `
499 width : 15px; 500 width : 15px;
500 `; 501 `;
501 502
503 +export const MedicineDosageSetWrapper = styled.div `
504 + width : 80%;
505 +
506 + display : flex;
507 + flex-direction : column;
508 +
509 + justify-content : center;
510 + align-items : center;
511 +
512 + border : none;
513 +
514 + margin : 20px 0;
515 +
516 + height : 200px;
517 +`;
518 +
519 +export const MedicineDosageInfo = styled.div `
520 + font-size : 15px;
521 + font-weight : 500;
522 +
523 + color : #a0a0a0;
524 +
525 + width : 100%;
526 + margin : 0 0 20px 0;
527 +
528 + border : none;
529 + background-color : transparent;
530 +
531 + text-align : center;
532 +`;
533 +
534 +export const MedicineDosageInput = styled.input.attrs({
535 + type : 'number',
536 + min : '1',
537 + max : '3',
538 +}) `
539 + width : 40%;
540 +
541 + padding : 10px 20px;
542 + color : #337DFF;
543 + font-size : 20px;
544 +
545 + font-weight : 700;
546 +
547 + border : none;
548 + border-bottom : 1px solid #337DFF;
549 +
550 + display : flex;
551 + flex-direction : row;
552 +
553 + text-align : center;
554 +
555 + transition : .25s all;
556 +`;
557 +
558 +export const MedicineQRCodeWrapper = styled.div `
559 + width : 80%;
560 + height : 200px;
561 +
562 + display : flex;
563 + flex-direction : column;
564 +
565 + justify-content : center;
566 + align-items : center;
567 +
568 + margin : 20px 0;
569 +
570 + border : none;
571 +`;
572 +
573 +export const MedicineQRCodeInfo = styled.div `
574 + font-size : 15px;
575 + font-weight : 500;
576 +
577 + color : #a0a0a0;
578 +
579 + text-align : center;
580 +`;
581 +
582 +export const MedicineQRCode = styled.img `
583 + margin : 10px 0 0 0;
584 +
585 + height : 170px;
586 + width : 170px;
587 +`;
588 +
502 export const MedicinePrescribeButtonWrapper = styled.div ` 589 export const MedicinePrescribeButtonWrapper = styled.div `
503 margin : 20px 0 0 0; 590 margin : 20px 0 0 0;
504 591
......
This diff could not be displayed because it is too large.