From e254c5c23d39bfe595b22afc2b6ad39a9dd2cca8 Mon Sep 17 00:00:00 2001 From: thug0bin Date: Wed, 11 Mar 2026 23:42:13 +0900 Subject: [PATCH] =?UTF-8?q?feat(pmr):=20=ED=99=98=EC=9E=90=20=EC=A0=84?= =?UTF-8?q?=ED=99=94=EB=B2=88=ED=98=B8=20=ED=91=9C=EC=8B=9C/=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - API: 처방 조회 시 CD_PERSON.PHONE 반환 - API: PUT /api/members/{code}/phone - 전화번호 저장 - UI: 나이/성별 옆에 전화번호 뱃지 표시 - UI: 전화번호 없으면 '전화번호 추가' 클릭 가능 - UI: 클릭 시 모달에서 전화번호 입력/저장 --- backend/app.py | 36 +++++++++++ backend/pmr_api.py | 17 +++-- backend/templates/pmr.html | 128 ++++++++++++++++++++++++++++++++++++- 3 files changed, 172 insertions(+), 9 deletions(-) diff --git a/backend/app.py b/backend/app.py index d9f1163..0ced1f4 100644 --- a/backend/app.py +++ b/backend/app.py @@ -5193,6 +5193,42 @@ def api_member_detail(cuscode): return jsonify({'success': False, 'error': str(e)}), 500 +@app.route('/api/members//phone', methods=['PUT']) +def api_update_phone(cuscode): + """환자 전화번호 수정 API""" + try: + data = request.get_json() or {} + new_phone = data.get('phone', '').strip() + + # 길이 제한 (20자) + if len(new_phone) > 20: + return jsonify({'success': False, 'error': '전화번호는 20자를 초과할 수 없습니다.'}), 400 + + base_session = db_manager.get_session('PM_BASE') + + # PHONE 업데이트 + update_query = text(""" + UPDATE CD_PERSON + SET PHONE = :phone + WHERE CUSCODE = :cuscode + """) + result = base_session.execute(update_query, {'phone': new_phone, 'cuscode': cuscode}) + base_session.commit() + + if result.rowcount == 0: + return jsonify({'success': False, 'error': '해당 고객을 찾을 수 없습니다.'}), 404 + + return jsonify({ + 'success': True, + 'message': '전화번호가 저장되었습니다.', + 'phone': new_phone + }) + + except Exception as e: + logging.error(f"전화번호 수정 오류: {e}") + return jsonify({'success': False, 'error': str(e)}), 500 + + @app.route('/api/members//cusetc', methods=['PUT']) def api_update_cusetc(cuscode): """특이(참고)사항 수정 API""" diff --git a/backend/pmr_api.py b/backend/pmr_api.py index 35a8629..6a9718f 100644 --- a/backend/pmr_api.py +++ b/backend/pmr_api.py @@ -431,20 +431,24 @@ def get_prescription_detail(prescription_id): 'name_2': disease_name_2 } - # 환자 특이사항(CUSETC) 조회 - CD_PERSON 테이블 + # 환자 특이사항(CUSETC) + 전화번호 조회 - CD_PERSON 테이블 cusetc = '' + phone = '' cus_code = rx_row.CusCode if cus_code: try: # PM_BASE.dbo.CD_PERSON에서 조회 cursor.execute(""" - SELECT CUSETC FROM PM_BASE.dbo.CD_PERSON WHERE CUSCODE = ? + SELECT CUSETC, PHONE, TEL_NO, PHONE2 FROM PM_BASE.dbo.CD_PERSON WHERE CUSCODE = ? """, (cus_code,)) person_row = cursor.fetchone() - if person_row and person_row.CUSETC: - cusetc = person_row.CUSETC + if person_row: + if person_row.CUSETC: + cusetc = person_row.CUSETC + # 전화번호 (PHONE, TEL_NO, PHONE2 중 하나) + phone = person_row.PHONE or person_row.TEL_NO or person_row.PHONE2 or '' except Exception as e: - logging.warning(f"특이사항 조회 실패: {e}") + logging.warning(f"환자정보 조회 실패: {e}") conn.close() @@ -467,7 +471,8 @@ def get_prescription_detail(prescription_id): 'cus_code': rx_row.CusCode, # 호환성 'age': age, 'gender': gender, - 'cusetc': cusetc # 특이사항 + 'cusetc': cusetc, # 특이사항 + 'phone': phone # 전화번호 }, 'disease_info': disease_info, 'medications': medications, diff --git a/backend/templates/pmr.html b/backend/templates/pmr.html index 7387485..014ebcc 100644 --- a/backend/templates/pmr.html +++ b/backend/templates/pmr.html @@ -254,6 +254,29 @@ transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); } + + /* 전화번호 뱃지 */ + .detail-header .phone-badge { + cursor: pointer; + margin-left: 10px; + padding: 3px 10px; + border-radius: 12px; + font-size: 0.85rem; + transition: all 0.2s; + } + .detail-header .phone-badge.has-phone { + background: rgba(255,255,255,0.25); + color: #fff; + } + .detail-header .phone-badge.no-phone { + background: rgba(255,255,255,0.1); + color: rgba(255,255,255,0.7); + border: 1px dashed rgba(255,255,255,0.4); + } + .detail-header .phone-badge:hover { + background: rgba(255,255,255,0.35); + transform: scale(1.05); + } .detail-header .cusetc-inline .cusetc-label { font-weight: 600; margin-right: 6px; @@ -1313,6 +1336,25 @@ + +
+
+
+

📞 환자 전화번호

+ +
+
+
+ +
💡 하이픈(-) 포함해서 입력하세요
+
+ +
+
+
@@ -1501,19 +1543,28 @@ pre_serial: prescriptionId, cus_code: data.patient.cus_code || data.patient.code, name: data.patient.name, + age: data.patient.age, + gender: data.patient.gender, st1: data.disease_info?.code_1 || '', st1_name: data.disease_info?.name_1 || '', st2: data.disease_info?.code_2 || '', st2_name: data.disease_info?.name_2 || '', medications: data.medications || [], - cusetc: data.patient.cusetc || '' // 특이사항 + cusetc: data.patient.cusetc || '', // 특이사항 + phone: data.patient.phone || '' // 전화번호 }; // 헤더 업데이트 document.getElementById('detailHeader').style.display = 'block'; document.getElementById('detailName').textContent = data.patient.name || '이름없음'; - document.getElementById('detailInfo').textContent = - `${data.patient.age || '-'}세 / ${data.patient.gender || '-'} / ${data.patient.birthdate || '-'}`; + + // 나이/성별 + 전화번호 표시 + const phone = data.patient.phone || ''; + const phoneDisplay = phone + ? `📞 ${phone}` + : `📞 전화번호 추가`; + document.getElementById('detailInfo').innerHTML = + `${data.patient.age || '-'}세 / ${data.patient.gender || '-'} ${phoneDisplay}`; // 질병 정보 표시 (각각 별도 뱃지) let diseaseHtml = ''; @@ -2065,6 +2116,77 @@ } } + // ───────────────────────────────────────────────────────────── + // 전화번호 모달 함수들 + // ───────────────────────────────────────────────────────────── + + function openPhoneModal() { + if (!currentPrescriptionData) { + alert('❌ 먼저 환자를 선택하세요.'); + return; + } + + const modal = document.getElementById('phoneModal'); + const patientInfo = document.getElementById('phonePatientInfo'); + const input = document.getElementById('phoneInput'); + + patientInfo.innerHTML = ` + ${currentPrescriptionData.name || '환자'} + 고객코드: ${currentPrescriptionData.cus_code || '-'} + `; + + input.value = currentPrescriptionData.phone || ''; + modal.style.display = 'flex'; + input.focus(); + } + + function closePhoneModal() { + document.getElementById('phoneModal').style.display = 'none'; + } + + async function savePhone() { + if (!currentPrescriptionData || !currentPrescriptionData.cus_code) { + alert('❌ 환자 정보가 없습니다.'); + return; + } + + const input = document.getElementById('phoneInput'); + const newPhone = input.value.trim(); + const cusCode = currentPrescriptionData.cus_code; + + try { + const res = await fetch(`/api/members/${cusCode}/phone`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ phone: newPhone }) + }); + + const data = await res.json(); + + if (data.success) { + currentPrescriptionData.phone = newPhone; + updatePhoneBadge(newPhone); + closePhoneModal(); + showPaaiToast(currentPrescriptionData.name, '전화번호가 저장되었습니다.', 'completed'); + } else { + alert('❌ ' + (data.error || '저장 실패')); + } + } catch (err) { + alert('❌ 오류: ' + err.message); + } + } + + function updatePhoneBadge(phone) { + const detailInfo = document.getElementById('detailInfo'); + if (!detailInfo || !currentPrescriptionData) return; + + const phoneDisplay = phone + ? `📞 ${phone}` + : `📞 전화번호 추가`; + detailInfo.innerHTML = + `${currentPrescriptionData.age || '-'}세 / ${currentPrescriptionData.gender || '-'} ${phoneDisplay}`; + } + // ───────────────────────────────────────────────────────────── // PAAI (Pharmacist Assistant AI) 함수들 - 비동기 토스트 방식 // ─────────────────────────────────────────────────────────────