Toggle navigation
Toggle navigation
This project
Loading...
Sign in
2021-1-capstone-design1
/
RIT_Project1
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
1
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
박권수
2021-09-16 21:30:26 +0900
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
e94de2888ed601f4911b4fc71186999eaa1e1b52
e94de288
2 parents
7a307931
677ab067
feat. 회원 가입 시 병원 검색, 등록
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
485 additions
and
26 deletions
server/src/api/auth/auth.ctrl.js
server/src/api/auth/index.js
server/src/lib/UpdatingMedicineInfo.js
web/src/api/api-auth.ts
web/src/views/register/RegisterContainer.tsx
web/src/views/register/RegisterPresenter.tsx
web/src/views/register/RegisterStyled.tsx
server/src/api/auth/auth.ctrl.js
View file @
e94de28
...
...
@@ -5,6 +5,7 @@ const Profile = require('../../models/profile');
const
DoctorInfo
=
require
(
'../../models/doctorInfo'
);
const
Joi
=
require
(
'joi'
);
const
jwt
=
require
(
'jsonwebtoken'
);
const
axios
=
require
(
'axios'
);
exports
.
register
=
async
(
ctx
)
=>
{
...
...
@@ -66,6 +67,29 @@ exports.register = async(ctx) => {
};
exports
.
searchHospital
=
async
ctx
=>
{
const
{
hospitalNm
,
page
,
}
=
ctx
.
query
;
const
pageSlice
=
5
;
const
url
=
'http://apis.data.go.kr/B551182/hospInfoService1/getHospBasisList1'
;
let
queryParams
=
'?'
+
encodeURIComponent
(
'ServiceKey'
)
+
'='
+
process
.
env
.
SERVICE_KEY
;
queryParams
+=
'&'
+
encodeURIComponent
(
'pageNo'
)
+
'='
+
encodeURIComponent
(
page
);
queryParams
+=
'&'
+
encodeURIComponent
(
'numOfRows'
)
+
'='
+
encodeURIComponent
(
pageSlice
);
queryParams
+=
'&'
+
encodeURIComponent
(
'yadmNm'
)
+
'='
+
encodeURIComponent
(
hospitalNm
);
const
result
=
await
axios
.
get
(
url
+
queryParams
);
ctx
.
status
=
200
;
ctx
.
body
=
{
totalPage
:
Math
.
ceil
(
result
.
data
.
response
.
body
.
totalCount
/
pageSlice
),
hospitalList
:
result
.
data
.
response
.
body
.
items
.
item
,
};
};
exports
.
doctorRegister
=
async
ctx
=>
{
const
{
userId
,
...
...
server/src/api/auth/index.js
View file @
e94de28
...
...
@@ -12,6 +12,14 @@ const auth = new Router()
auth
.
post
(
'/register'
,
authCtrl
.
register
)
/**
* 병원 검색
* url : http://localhost:4000/api/auth/hospital
* request parameter : hospitalNm
* return : xml type data
*/
auth
.
get
(
'/hospital'
,
authCtrl
.
searchHospital
);
/**
* 회원가입 (email type) : 의사 회원가입
* url : http://localhost:4000/api/auth/register/doctor
* request parameter : userId, password, passwordCheck, doctorInfo
...
...
server/src/lib/UpdatingMedicineInfo.js
View file @
e94de28
...
...
@@ -11,6 +11,7 @@ exports.updateMedicineInfo = async() => {
//queryUrl을 return하는 함수 : 한 페이지에 100개의 item씩 요청할 수 있다.
const
getQueryURL
=
(
i
)
=>
{
const
url
=
'http://apis.data.go.kr/1471000/DrbEasyDrugInfoService/getDrbEasyDrugList'
;
// eslint-disable-next-line no-undef
const
queryParams
=
'?'
+
encodeURIComponent
(
'ServiceKey'
)
+
'='
+
process
.
env
.
SERVICE_KEY
;
const
pageNum
=
'&'
+
encodeURIComponent
(
'pageNo'
)
+
'='
+
encodeURIComponent
(
i
);
const
numOfItem
=
'&'
+
encodeURIComponent
(
'numOfRows'
)
+
'='
+
encodeURIComponent
(
100
);
...
...
@@ -24,6 +25,7 @@ const getItemsList = async(queryUrl) => {
let
i
=
1
,
getItem
=
null
,
items
=
null
;
const
result
=
[];
// eslint-disable-next-line no-constant-condition
while
(
true
)
{
getItem
=
await
axios
.
get
(
queryUrl
(
i
));
items
=
getItem
.
data
.
body
.
items
;
...
...
web/src/api/api-auth.ts
View file @
e94de28
...
...
@@ -5,6 +5,15 @@ export default {
return
client
.
post
(
'/auth/register'
,
Data
);
},
searchHospital
:
(
hospitalNm
:
string
,
page
:
number
)
=>
{
return
client
.
get
(
'/auth/hospital'
,
{
params
:
{
hospitalNm
,
page
,
},
});
},
registerDoctor
:
(
Data
:
any
)
=>
{
return
client
.
post
(
'/auth/register/doctor'
,
Data
);
},
...
...
web/src/views/register/RegisterContainer.tsx
View file @
e94de28
import React, { useState, useEffect } from "react";
import { RouteComponentProps } from 'react-router-dom';
import { useRecoilValue } from "recoil";
import { useRecoilValue
, useRecoilState
} from "recoil";
import * as recoilUtil from '../../util/recoilUtil';
import validator from 'validator';
...
...
@@ -11,7 +11,6 @@ import Header from '../../components/Header';
import RegisterPresenter from "./RegisterPresenter";
import { authApi } from '../../api';
import { resourceLimits } from "worker_threads";
// eslint-disable-next-line @typescript-eslint/no-empty-interface
...
...
@@ -20,6 +19,7 @@ interface RegisterProps extends RouteComponentProps {}
const RegisterContainer = (props : RegisterProps) => {
const token = useRecoilValue(recoilUtil.token);
const [loading, setLoading] = useRecoilState(recoilUtil.loading);
const [registerForm, setRegisterForm] = useState<any>({
userId : '',
...
...
@@ -38,6 +38,12 @@ const RegisterContainer = (props : RegisterProps) => {
const [page, setPage] = useState<number>(1);
const [error, setError] = useState<string | null>(null);
const [searchHospital, setSearchHospital] = useState<boolean>(false);
const [hospitalNm, setHospitalNm] = useState<string>('');
const [hospitalSearchPage, setHospitalSearchPage] = useState<number>(1);
const [hospitalSearchPageList, setHospitalSearchPageList] = useState<number[]>([1]);
const [hospitalList, setHospitalList] = useState<any[]>([]);
const [selectHospital, setSelectHospital] = useState<any>(null);
const fetchData = async() => {
...
...
@@ -46,7 +52,7 @@ const RegisterContainer = (props : RegisterProps) => {
if (result.statusText === 'OK') {
props.history.push('/');
}
}
}
};
const onCancleRegister = () => {
...
...
@@ -126,23 +132,7 @@ const RegisterContainer = (props : RegisterProps) => {
};
const onSetHospitalNm = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
hospitalNm : e.target.value,
},
});
};
const onSetHospitalAddr = (e : React.ChangeEvent<HTMLInputElement>) => {
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
hospitalAddr : e.target.value,
},
});
setHospitalNm(e.target.value);
};
const onSetContact = (e : React.ChangeEvent<HTMLInputElement>) => {
...
...
@@ -175,6 +165,49 @@ const RegisterContainer = (props : RegisterProps) => {
});
};
const onSearchHospital = async () => {
try {
setLoading(true);
setSearchHospital(true);
const result = await authApi.searchHospital(hospitalNm, hospitalSearchPage);
if(result.statusText === 'OK') {
setLoading(false);
setHospitalSearchPageList(new Array(result.data.totalPage).fill(null).map((item : null, index : number) => index + 1));
setHospitalList(result.data.hospitalList.length ? result.data.hospitalList : [result.data.hospitalList]);
}
} catch(e : any) {
setLoading(false);
Alert.onError('알 수 없는 에러로 검색에 실패했습니다.', () => null);
}
};
const onSetSearchPrevPage = () => {
//set Prev Page
const pageSlice = 5;
if(hospitalSearchPage > pageSlice) {
setHospitalSearchPage(Math.floor((hospitalSearchPage - 1) / pageSlice) * pageSlice);
}
};
const onSetSearchNextPage = () => {
//set Next Page
const pageSlice = 5;
if(hospitalSearchPage <= Math.floor((hospitalSearchPageList.length - 1) / pageSlice) * pageSlice) {
setHospitalSearchPage(Math.ceil(hospitalSearchPage / pageSlice) * pageSlice + 1);
}
};
const onCancelSearchHospital = () => {
Alert.onCheck('병원 등록이 취소됩니다. 계속하시겠습니까?', () => {
setSearchHospital(false);
setHospitalNm('');
setHospitalSearchPage(1);
setHospitalSearchPageList([1]);
setHospitalList([]);
setSelectHospital(null);
}, () => null);
};
const onSubmitButton = () => {
if(error) {
Alert.onError(error, () => null);
...
...
@@ -192,20 +225,54 @@ const RegisterContainer = (props : RegisterProps) => {
if(result.data === 'Created') {
Alert.onSuccess('회원가입 성공, 관리자의 승인을 대기하세요.', () => props.history.push('/login'));
}
} catch(e) {
} catch(e
: any
) {
Alert.onError(e.response.data.error, () => null);
}
};
Alert.onCheck('입력하신 정보로 회원가입을 진행하시겠습니까?', onRegisterDoctor, () => null);
if(selectHospital) {
Alert.onCheck('입력하신 정보로 회원가입을 진행하시겠습니까?', onRegisterDoctor, () => null);
} else {
Alert.onError('검색 버튼을 눌러 병원을 선택해주세요.', () => null);
}
}
};
useEffect(() => {
validateRegisterForm();
}, [registerForm, page]);
useEffect(() => {
if(selectHospital) {
setHospitalNm(selectHospital.yadmNm);
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
hospitalNm : selectHospital.yadmNm,
hospitalAddr : selectHospital.addr,
},
});
} else {
setHospitalNm('');
setRegisterForm({
...registerForm,
info : {
...registerForm.info,
hospitalNm : '',
hospitalAddr : '',
},
});
}
}, [selectHospital]);
useEffect(() => {
if(searchHospital) onSearchHospital();
}, [hospitalSearchPage]);
useEffect(() => {
fetchData();
...
...
@@ -228,12 +295,27 @@ const RegisterContainer = (props : RegisterProps) => {
onSetPassword = {onSetPassword}
onSetPasswordCheck = {onSetPasswordCheck}
onSetDoctorLicense = {onSetDoctorLicense}
hospitalNm = {hospitalNm}
setHospitalNm = {setHospitalNm}
onSetHospitalNm = {onSetHospitalNm}
onSetHospitalAddr = {onSetHospitalAddr}
onSetContact = {onSetContact}
onSetDoctorType = {onSetDoctorType}
onSetDoctorNm = {onSetDoctorNm}
onSubmitButton = {onSubmitButton}
searchHospital = {searchHospital}
setSearchHospital = {setSearchHospital}
onSearchHospital = {onSearchHospital}
hospitalSearchPage = {hospitalSearchPage}
setHospitalSearchPage = {setHospitalSearchPage}
hospitalSearchPageList = {hospitalSearchPageList}
onSetSearchPrevPage = {onSetSearchPrevPage}
onSetSearchNextPage = {onSetSearchNextPage}
onCancelSearchHospital = {onCancelSearchHospital}
hospitalList = {hospitalList}
selectHospital = {selectHospital}
setSelectHospital = {setSelectHospital}
/>
</>
)
...
...
web/src/views/register/RegisterPresenter.tsx
View file @
e94de28
This diff is collapsed. Click to expand it.
web/src/views/register/RegisterStyled.tsx
View file @
e94de28
import styled from 'styled-components';
import styled, { keyframes } from 'styled-components';
const ModalOn = keyframes `
0% {
background-color : rgba(52, 52, 52, .0);
}
20% {
background-color : rgba(52, 52, 52, .2);
}
40% {
background-color : rgba(52, 52, 52, .4);
}
60% {
background-color : rgba(52, 52, 52, .5);
}
80% {
background-color : rgba(52, 52, 52, .6);
}
100% {
background-color : rgba(52, 52, 52, .7);
}
`;
export const Container = styled.div `
...
...
@@ -10,6 +33,274 @@ export const Container = styled.div `
align-items : center;
`;
export const ModalContainer = styled.div `
height : 100%;
width : 100%;
z-index : 99;
position : absolute;
display : flex;
flex-direction : column;
animation : ${ModalOn} .5s;
background-color : rgba(52, 52, 52, .7);
`;
export const ModalClsButtonWrapper = styled.div `
flex : 1;
display : flex;
justify-content : flex-end;
align-items : center;
padding : 0 20px;
border : none;
background-color : transprent;
`;
export const ModalClsButton = styled.button `
border : none;
background-color : transparent;
cursor : pointer;
color : #fff;
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
transition : .25s all;
&:hover {
opacity : .5;
}
`;
export const ModalClsButtonImg = styled.img `
height : 20px;
width : 20px;
margin : 0 10px 0 0;
`;
export const ModalClsButtonText = styled.div `
font-size : 18px;
font-weight : 700;
`;
export const ModalContentWrapper = styled.div `
flex : 8;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
border : none;
`;
export const ModalContent = styled.div `
width : 600px;
height : 400px;
background-color : #fff;
border : 1.2px solid #337DFF;
border-radius : 5px;
display : flex;
flex-direction : column;
justify-content : center;
align-items : center;
`;
export const SearchTitle = styled.div `
font-weight : 600;
font-size : 20;
color : #337DFF;
`;
export const HospitalListWrapper = styled.div `
margin : 20px 0;
height : 200px;
width : 80%;
border : 1px solid #337DFF;
display : flex;
flex-direction : column;
`;
export const HospitalListInfo = styled.div `
height : 20px;
width : 100%;
border : none;
border-bottom : 1px solid #ddd;
display : flex;
flex-direction : row;
`;
export const HospitalListInfoEach = styled.div<{isLast : boolean}> `
flex : ${props => props.isLast ? '1' : '3'};
display : flex;
align-items : center;
justify-content : center;
font-size : 14px;
font-weight : 500;
color : #343434;
border : none;
border-right : ${props => props.isLast ? 'none' : '1px solid #ddd'};
padding : 3px 5px;
`;
export const HospitalListEach = styled.div `
min-height : 35px;
max-height : 35px;
width : 100%;
display : flex;
flex-direction : row;
border : none;
border-bottom : 1px solid #ddd;
`;
export const HospitalListEachInfo = styled.div<{isLast : boolean}> `
flex : ${props => props.isLast ? '1' : '3'};
display : flex;
font-size : 12px;
font-weight : 500;
justify-content : center;
align-items : center;
border : none;
border-right : ${props => props.isLast ? 'none' : '1px solid #ddd'};
padding : 3px 5px;
`;
export const CheckButton = styled.button `
border : none;
background-color : transparent;
height : 15px;
width : 15px;
display : flex;
flex-direction : row;
justify-content : center;
cursor : pointer;
transition : .25s all;
&:hover {
opacity : .5;
}
`;
export const CheckButtonImg = styled.img `
height : 15px;
width : 15px;
`;
export const PageWrapper = styled.div `
width : 50%;
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
gap : 2%;
`;
export const PageButton = styled.button<{isSelect : boolean}> `
height : 18px;
width : 18px;
display : flex;
align-items : center;
justify-content : center;
border : none;
border-radius : 4px;
background-color : ${props => props.isSelect ? '#337DFF' : 'transparent'};
color : ${props => props.isSelect ? '#fff' : '#343434'};
font-size : 12px;
font-weight : 600;
cursor : pointer;
transition : .25s all;
&:hover {
opacity : .7;
}
`;
export const PageArrowImg = styled.img `
height : 15px;
width : 15px;
`;
export const ModalButtonWrapper = styled.div `
margin : 20px 0 0 0;
width : 50%;
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
border : none;
gap : 10%;
`;
export const ModalButton = styled.div<{isCloseButton : boolean}> `
padding : 2.5% 10%;
cursor : pointer;
border : 1px solid ${props => props.isCloseButton ? '#343434' : '#337DFF'};
background-color : ${props => props.isCloseButton ? 'transparent' : '#337DFF'};
border-radius : 5px;
color : ${props => props.isCloseButton ? '#343434' : '#fff'};
font-weight : 600;
font-size : 16px;
transition : .25s all;
&:hover {
opacity : .7;
}
`
export const RegisterWrapper = styled.div `
width : 35%;
border : none;
...
...
@@ -24,10 +315,9 @@ export const RegisterWrapper = styled.div `
padding : 30px 3px;
box-shadow: 0px 0px 10px #a0a0a0;
`;
export const RegisterBackButtonWrapper = styled.div `
width : 100%;
border : none;
...
...
@@ -97,6 +387,18 @@ export const RegisterInputText = styled.div `
`;
export const RegisterInputWrapperForSearch = styled.div `
display : flex;
flex-direction : row;
justify-content : center;
width : 100%;
border : none;
background-color : transparent;
`;
export const RegisterInput = styled.input `
width : 80%;
padding : 5px 10px;
...
...
@@ -111,6 +413,38 @@ export const RegisterInput = styled.input `
}
`;
export const RegisterInputSearchButton = styled.button `
position : absolute;
height : 25px;
width : 25px;
align-self : end;
margin : 0 0 1px 24%;
background-color : transparent;
border : none;
transition : .25s all;
&:hover {
opacity : .5;
}
display : flex;
flex-direction : row;
justify-content : center;
align-items : center;
cursor : pointer;
`;
export const RegisterInputSearchButtonImg = styled.img `
height : 20px;
width : 20px;
`;
export const RegisterButtonWrapper = styled.div `
margin : 20px 0 0 0;
...
...
Please
register
or
login
to post a comment