박권수

feat. 처방API, QRCode 생성 등

...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
23 "moment": "^2.29.1", 23 "moment": "^2.29.1",
24 "moment-timezone": "^0.5.33", 24 "moment-timezone": "^0.5.33",
25 "mqtt": "^4.2.6", 25 "mqtt": "^4.2.6",
26 - "node-cron": "^3.0.0" 26 + "node-cron": "^3.0.0",
27 + "qrcode": "^1.4.4"
27 }, 28 },
28 "devDependencies": { 29 "devDependencies": {
29 "eslint": "^7.32.0" 30 "eslint": "^7.32.0"
......
...@@ -9,8 +9,13 @@ const Feedback = require('../../models/feedback'); ...@@ -9,8 +9,13 @@ const Feedback = require('../../models/feedback');
9 const Hub = require('../../models/hub'); 9 const Hub = require('../../models/hub');
10 const PatientInfo = require('../../models/patientInfo'); 10 const PatientInfo = require('../../models/patientInfo');
11 const DoctorInfo = require('../../models/doctorInfo'); 11 const DoctorInfo = require('../../models/doctorInfo');
12 +const PrescribeInfo = require('../../models/prescribeInfo');
13 +
12 const jwt = require('jsonwebtoken'); 14 const jwt = require('jsonwebtoken');
13 15
16 +const { uploadQrCode, viewQrCode } = require('../../util/GoogleCloudStorage');
17 +const QrCodeUtil = require('../../util/QrCodeUtil');
18 +
14 19
15 /** 20 /**
16 * 현재 로그인한 유저의 의사 정보를 가져온다 21 * 현재 로그인한 유저의 의사 정보를 가져온다
...@@ -342,6 +347,11 @@ exports.writeReqBottleFeedback = async ctx => { ...@@ -342,6 +347,11 @@ exports.writeReqBottleFeedback = async ctx => {
342 347
343 }; 348 };
344 349
350 +/**
351 + * 이메일로 환자를 검색한다.
352 + * @param {*} ctx
353 + * @returns
354 + */
345 exports.searchPatientById = async ctx => { 355 exports.searchPatientById = async ctx => {
346 const token = ctx.req.headers.authorization; 356 const token = ctx.req.headers.authorization;
347 if (!token || !token.length) { 357 if (!token || !token.length) {
...@@ -482,4 +492,108 @@ exports.removeReqPatient = async ctx => { ...@@ -482,4 +492,108 @@ exports.removeReqPatient = async ctx => {
482 492
483 ctx.status = 200; 493 ctx.status = 200;
484 494
495 +};
496 +
497 +/**
498 + * 특정 환자에게 특정 약을 처방한다
499 + * @param {*} ctx
500 + * http methods : post
501 + */
502 +exports.prescribeMedicine = async ctx => {
503 + const token = ctx.req.headers.authorization;
504 + if(!token || !token.length) {
505 + ctx.status = 401;
506 + return;
507 + }
508 +
509 + // eslint-disable-next-line no-undef
510 + const { userId } = jwt.verify(token, process.env.JWT_SECRET);
511 + const user = await User.findByUserId(userId);
512 + if(!user || user.userTypeCd !== 'DOCTOR') {
513 + ctx.status = 403;
514 + ctx.body = {
515 + error : '권한 없는 유저',
516 + };
517 + return;
518 + }
519 +
520 +
521 + const {
522 + patientId,
523 + medicineId,
524 + dosage,
525 + } = ctx.request.body;
526 +
527 +
528 + const patientInfo = await PatientInfo.findOne({
529 + patientId,
530 + doctorId : userId,
531 + useYn : 'Y',
532 + })
533 + if(!patientInfo) {
534 + ctx.status = 403;
535 + ctx.body = {
536 + error : '권한 없는 환자',
537 + };
538 + return;
539 + }
540 +
541 + const medicine = await Medicine.findOne({
542 + medicineId
543 + });
544 + if(!medicine) {
545 + ctx.status = 404;
546 + ctx.body = {
547 + error : '존재하지 않는 약',
548 + };
549 + return;
550 + }
551 +
552 +
553 + const qrCodeResult = await QrCodeUtil.generateQrCode_prescribe({
554 + medicine,
555 + dosage,
556 + patientId,
557 + doctorId : userId,
558 + });
559 + if(!qrCodeResult) {
560 + ctx.status = 400;
561 + ctx.body = {
562 + error : 'QR 코드 생성 에러',
563 + };
564 + return;
565 + }
566 +
567 + const qrCodeUrl = await uploadQrCode(qrCodeResult);
568 + if(!qrCodeUrl) {
569 + ctx.status = 400;
570 + ctx.body = {
571 + error : 'QR 코드 생성 후 서버 업로드 에러',
572 + };
573 + return;
574 + }
575 +
576 + const prescribeInfo = new PrescribeInfo({
577 + doctorId : userId,
578 + patientId,
579 + dosage,
580 + medicineId,
581 + qrCodeUrl,
582 + });
583 + await prescribeInfo.save();
584 +
585 + //특이사항에 처방기록 저장
586 + patientInfo.updateInfo(`${medicine.name}, 하루 ${dosage}알 처방`);
587 + await patientInfo.save();
588 +
589 +
590 + const { qrCodeFileName } = qrCodeResult;
591 + const qrCode = await viewQrCode({ qrCodeFileName });
592 +
593 + ctx.status = 200;
594 + ctx.body = {
595 + qrCode,
596 + };
597 +
598 +
485 }; 599 };
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -7,7 +7,7 @@ const doctor = new Router(); ...@@ -7,7 +7,7 @@ const doctor = new Router();
7 /** 7 /**
8 * 현재 로그인한 유저(의사)의 정보를 가져옴. 8 * 현재 로그인한 유저(의사)의 정보를 가져옴.
9 * request parameter : token 9 * request parameter : token
10 - * url : http://localhost:4000/doctor/ 10 + * url : http://localhost:4000/api/doctor/
11 * return : doctor's Info 11 * return : doctor's Info
12 */ 12 */
13 doctor.get('/', doctorCtrl.getDoctorsInfo); 13 doctor.get('/', doctorCtrl.getDoctorsInfo);
...@@ -15,7 +15,7 @@ doctor.get('/', doctorCtrl.getDoctorsInfo); ...@@ -15,7 +15,7 @@ doctor.get('/', doctorCtrl.getDoctorsInfo);
15 /** 15 /**
16 * 현재 로그인한 유저(의사)의 관리 환자 목록을 가져옴 16 * 현재 로그인한 유저(의사)의 관리 환자 목록을 가져옴
17 * request parameter 17 * request parameter
18 - * url : http://localhost:4000/doctor/patient 18 + * url : http://localhost:4000/api/doctor/patient
19 * return : patient List 19 * return : patient List
20 */ 20 */
21 doctor.get('/patient', doctorCtrl.getPatientList); 21 doctor.get('/patient', doctorCtrl.getPatientList);
...@@ -23,7 +23,7 @@ doctor.get('/patient', doctorCtrl.getPatientList); ...@@ -23,7 +23,7 @@ doctor.get('/patient', doctorCtrl.getPatientList);
23 /** 23 /**
24 * 현재 로그인한 유저(의사)의 관리 환자 상세 정보를 가져옴 24 * 현재 로그인한 유저(의사)의 관리 환자 상세 정보를 가져옴
25 * request parameter : patient Id 25 * request parameter : patient Id
26 - * url : http://localhost:4000/doctor/patient/:patientId 26 + * url : http://localhost:4000/api/doctor/patient/:patientId
27 * return : patient Detail 27 * return : patient Detail
28 */ 28 */
29 doctor.get('/patient/:patientId', doctorCtrl.getPatientDetail); 29 doctor.get('/patient/:patientId', doctorCtrl.getPatientDetail);
...@@ -31,7 +31,7 @@ doctor.get('/patient/:patientId', doctorCtrl.getPatientDetail); ...@@ -31,7 +31,7 @@ doctor.get('/patient/:patientId', doctorCtrl.getPatientDetail);
31 /** 31 /**
32 * 현재 로그인한 유저(의사)의 관리 약병 상세 정보를 가져옴 32 * 현재 로그인한 유저(의사)의 관리 약병 상세 정보를 가져옴
33 * request parameter : bottle Id 33 * request parameter : bottle Id
34 - * url : http://localhost:4000/doctor/bottle/:bottleId 34 + * url : http://localhost:4000/api/doctor/bottle/:bottleId
35 * return : bottle Detail 35 * return : bottle Detail
36 */ 36 */
37 doctor.get('/bottle/:bottleId', doctorCtrl.getBottleDetail); 37 doctor.get('/bottle/:bottleId', doctorCtrl.getBottleDetail);
...@@ -39,7 +39,7 @@ doctor.get('/bottle/:bottleId', doctorCtrl.getBottleDetail); ...@@ -39,7 +39,7 @@ doctor.get('/bottle/:bottleId', doctorCtrl.getBottleDetail);
39 /** 39 /**
40 * 현재 로그인한 유저(의사)의 특정 관리 환자의 특이사항을 기록함 40 * 현재 로그인한 유저(의사)의 특정 관리 환자의 특이사항을 기록함
41 * request parameter : reqUserId, info 41 * request parameter : reqUserId, info
42 - * url : http://localhost:4000/doctor/patient 42 + * url : http://localhost:4000/api/doctor/patient
43 * return : null 43 * return : null
44 */ 44 */
45 doctor.patch('/patient', doctorCtrl.writeReqPatientReport); 45 doctor.patch('/patient', doctorCtrl.writeReqPatientReport);
...@@ -47,7 +47,7 @@ doctor.patch('/patient', doctorCtrl.writeReqPatientReport); ...@@ -47,7 +47,7 @@ doctor.patch('/patient', doctorCtrl.writeReqPatientReport);
47 /** 47 /**
48 * 현재 로그인한 유저(의사)의 특정 관리 환자의 약병의 피드백을 등록함. 48 * 현재 로그인한 유저(의사)의 특정 관리 환자의 약병의 피드백을 등록함.
49 * request parameter : bottleId, fdbType, feedback 49 * request parameter : bottleId, fdbType, feedback
50 - * url : http://localhost:4000/doctor/bottle 50 + * url : http://localhost:4000/api/doctor/bottle
51 * return : null 51 * return : null
52 */ 52 */
53 doctor.post('/bottle', doctorCtrl.writeReqBottleFeedback); 53 doctor.post('/bottle', doctorCtrl.writeReqBottleFeedback);
...@@ -55,7 +55,7 @@ doctor.post('/bottle', doctorCtrl.writeReqBottleFeedback); ...@@ -55,7 +55,7 @@ doctor.post('/bottle', doctorCtrl.writeReqBottleFeedback);
55 /** 55 /**
56 * 현재 로그인한 유저(의사)가 이메일로 유저를 검색함 56 * 현재 로그인한 유저(의사)가 이메일로 유저를 검색함
57 * request parameter : patientId 57 * request parameter : patientId
58 - * url : http://localhost:4000/api/doctor/patient/search/:patientId 58 + * url : http://localhost:4000/api/api/doctor/patient/search/:patientId
59 * return : patient Info(simple) 59 * return : patient Info(simple)
60 */ 60 */
61 doctor.get('/patient/search/:patientId', doctorCtrl.searchPatientById); 61 doctor.get('/patient/search/:patientId', doctorCtrl.searchPatientById);
...@@ -63,7 +63,7 @@ doctor.get('/patient/search/:patientId', doctorCtrl.searchPatientById); ...@@ -63,7 +63,7 @@ doctor.get('/patient/search/:patientId', doctorCtrl.searchPatientById);
63 /** 63 /**
64 * 현재 로그인한 유저(의사)의 관리 환자를 등록함. 64 * 현재 로그인한 유저(의사)의 관리 환자를 등록함.
65 * request parameter : patientId 65 * request parameter : patientId
66 - * url : http://localhost:4000/doctor/patient 66 + * url : http://localhost:4000/api/doctor/patient
67 * return : null 67 * return : null
68 */ 68 */
69 doctor.post('/patient', doctorCtrl.registerNewPatient); 69 doctor.post('/patient', doctorCtrl.registerNewPatient);
...@@ -71,11 +71,18 @@ doctor.post('/patient', doctorCtrl.registerNewPatient); ...@@ -71,11 +71,18 @@ doctor.post('/patient', doctorCtrl.registerNewPatient);
71 /** 71 /**
72 * 현재 로그인한 유저(의사)의 특정 관리 환자를 삭제함. 72 * 현재 로그인한 유저(의사)의 특정 관리 환자를 삭제함.
73 * request parameter : patientId 73 * request parameter : patientId
74 - * url : http://localhost:4000/doctor/patient/:patientId 74 + * url : http://localhost:4000/api/doctor/patient/:patientId
75 * return : null 75 * return : null
76 */ 76 */
77 doctor.delete('/patient/:patientId', doctorCtrl.removeReqPatient); 77 doctor.delete('/patient/:patientId', doctorCtrl.removeReqPatient);
78 78
79 +/**
80 + * 의사가 관리하는 환자에 대해 특정 약을 처방함
81 + * request paramter : patientId, medicineId, dosage
82 + * url : http://localhost:4000/api/doctor/prescribe
83 + * return : null
84 + */
85 +doctor.post('/prescribe', doctorCtrl.prescribeMedicine);
86 +
79 87
80 -module.exports = doctor;
81 -
...\ No newline at end of file ...\ No newline at end of file
88 +module.exports = doctor;
...\ No newline at end of file ...\ No newline at end of file
......
1 +const mongoose = require('mongoose');
2 +
3 +const Schema = mongoose.Schema;
4 +
5 +const PrescribeInfoSchema = new Schema({
6 + doctorId : { type : String, require : true, },
7 + patientId : { type : String, require : true, },
8 + medicineId : { type : Number, require : true, },
9 + dosage : { type : Number, require : true, },
10 + qrCodeUrl : { type : String, require : true, },
11 +});
12 +
13 +
14 +module.exports = mongoose.model('PrescribeInfo', PrescribeInfoSchema);
...\ No newline at end of file ...\ No newline at end of file
1 const { Storage } = require('@google-cloud/storage'); 1 const { Storage } = require('@google-cloud/storage');
2 +const fs = require('fs');
2 3
3 const storage = new Storage(); 4 const storage = new Storage();
4 const GoogleStorageUrl = 'https://storage.googleapis.com/'; 5 const GoogleStorageUrl = 'https://storage.googleapis.com/';
...@@ -7,19 +8,23 @@ const GoogleStorageUrl = 'https://storage.googleapis.com/'; ...@@ -7,19 +8,23 @@ const GoogleStorageUrl = 'https://storage.googleapis.com/';
7 //의사 아이디, 업로드할 파일명, 업로드할 파일 경로를 인자로 받아, File을 GCS에 업로드 후 GCS 주소를 반환 8 //의사 아이디, 업로드할 파일명, 업로드할 파일 경로를 인자로 받아, File을 GCS에 업로드 후 GCS 주소를 반환
8 exports.uploadDoctorLicense = async ({ userId, fileName, filePath }) => { 9 exports.uploadDoctorLicense = async ({ userId, fileName, filePath }) => {
9 const destination = userId + '_' + fileName; 10 const destination = userId + '_' + fileName;
10 - const result = await storage.bucket('doctor-info').upload(filePath, { 11 + try {
11 - destination, 12 + const result = await storage.bucket('doctor-info').upload(filePath, {
12 - }); 13 + destination,
13 - 14 + });
14 - const doctorLicenseUrl = GoogleStorageUrl + `${result[0].bucket.id}/${result[0].name}`; 15 +
15 - 16 + const doctorLicenseUrl = GoogleStorageUrl + `${result[0].bucket.id}/${result[0].name}`;
16 - return doctorLicenseUrl; 17 +
18 + return doctorLicenseUrl;
19 + } catch(e) {
20 + return null;
21 + }
17 }; 22 };
18 23
19 //의사 정보를 인자로 받아 해당 Doctor License의 Signed URL을 반환 24 //의사 정보를 인자로 받아 해당 Doctor License의 Signed URL을 반환
20 exports.viewDoctorLicense = async ({ doctorInfo }) => { 25 exports.viewDoctorLicense = async ({ doctorInfo }) => {
21 const fileName = doctorInfo.info.doctorLicense.split('/').pop(); 26 const fileName = doctorInfo.info.doctorLicense.split('/').pop();
22 - const file = new Storage().bucket('doctor-info').file(fileName); 27 + const file = storage.bucket('doctor-info').file(fileName);
23 const option = { 28 const option = {
24 version : 'v4', 29 version : 'v4',
25 expires : Date.now() + 1000 * 60 * 15, 30 expires : Date.now() + 1000 * 60 * 15,
...@@ -32,6 +37,36 @@ exports.viewDoctorLicense = async ({ doctorInfo }) => { ...@@ -32,6 +37,36 @@ exports.viewDoctorLicense = async ({ doctorInfo }) => {
32 }; 37 };
33 38
34 //의사 ID, 약 ID, 복용량을 인자로 받아, QR Code를 생성 39 //의사 ID, 약 ID, 복용량을 인자로 받아, QR Code를 생성
35 -exports.prescribeMedicine = async ({ doctorId, medicineId, dosage }) => { 40 +exports.uploadQrCode = async ({ directory, qrCodeFileName }) => {
36 - //toDo 41 + const destination = qrCodeFileName;
42 + try {
43 + //파일을 GCS에 업로드
44 + const result = await storage.bucket('prescribe-medicine-qrcode').upload(directory + qrCodeFileName, {
45 + destination
46 + });
47 +
48 + //업로드 후 파일 삭제
49 + fs.rm(directory + qrCodeFileName, () => {});
50 +
51 + const qrCodeUrl = GoogleStorageUrl + `${result[0].bucket.id}/${result[0].name}`;
52 +
53 + return qrCodeUrl;
54 + } catch(e) {
55 + return null;
56 + }
57 +};
58 +
59 +//생성된 QR코드의 signedUrl을 가져옴
60 +exports.viewQrCode = async ({ qrCodeFileName }) => {
61 + const fileName = qrCodeFileName;
62 + const file = storage.bucket('prescribe-medicine-qrcode').file(fileName);
63 + const option = {
64 + version : 'v4',
65 + expires : Date.now() + 1000 * 60 * 15,
66 + action : 'read',
67 + };
68 +
69 + const [signedUrl] = file ? await file.getSignedUrl(option) : [null];
70 +
71 + return signedUrl;
37 }; 72 };
...\ No newline at end of file ...\ No newline at end of file
......
1 +const QrCode = require('qrcode');
2 +const moment = require('moment');
3 +
4 +
5 +exports.generateQrCode_prescribe = async ({ medicine, dosage, patientId, doctorId }) => {
6 + const directory = "/Users/parkkwonsoo/Desktop/Project/Capstone_Design_1/server/data/";
7 +
8 + const now = moment().format('YYYY-MM-DD_HH:mm');
9 + const qrCodeFileName = `${now}_${doctorId}_${patientId}_${medicine.medicineId}_${dosage}.png`;
10 +
11 + try {
12 + await QrCode.toFile(
13 + directory + qrCodeFileName,
14 + `${medicine.name}/${medicine.medicineId}/${dosage}/${patientId}/${doctorId}`,
15 + {
16 + color : {
17 + dark : '#337DFF',
18 + light : '#FFF'
19 + },
20 + }
21 + );
22 +
23 + return {
24 + directory,
25 + qrCodeFileName,
26 + };
27 +
28 + } catch(e) {
29 + console.log(e);
30 + return null;
31 + }
32 +
33 +};
...\ No newline at end of file ...\ No newline at end of file
This diff could not be displayed because it is too large.