feat(pmr): 환자 전화번호 표시/수정 기능 추가
- API: 처방 조회 시 CD_PERSON.PHONE 반환
- API: PUT /api/members/{code}/phone - 전화번호 저장
- UI: 나이/성별 옆에 전화번호 뱃지 표시
- UI: 전화번호 없으면 '전화번호 추가' 클릭 가능
- UI: 클릭 시 모달에서 전화번호 입력/저장
This commit is contained in:
parent
4c033b0584
commit
e254c5c23d
@ -5193,6 +5193,42 @@ def api_member_detail(cuscode):
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/members/<cuscode>/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/<cuscode>/cusetc', methods=['PUT'])
|
||||
def api_update_cusetc(cuscode):
|
||||
"""특이(참고)사항 수정 API"""
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 전화번호 모달 -->
|
||||
<div class="cusetc-modal" id="phoneModal">
|
||||
<div class="cusetc-modal-content">
|
||||
<div class="cusetc-modal-header">
|
||||
<h3>📞 환자 전화번호</h3>
|
||||
<button class="cusetc-modal-close" onclick="closePhoneModal()">×</button>
|
||||
</div>
|
||||
<div class="cusetc-modal-body">
|
||||
<div class="cusetc-patient-info" id="phonePatientInfo"></div>
|
||||
<input type="tel" id="phoneInput" placeholder="010-0000-0000" style="width:100%;padding:12px;border:2px solid #e2e8f0;border-radius:8px;font-size:16px;text-align:center;">
|
||||
<div class="cusetc-hint">💡 하이픈(-) 포함해서 입력하세요</div>
|
||||
</div>
|
||||
<div class="cusetc-modal-footer">
|
||||
<button class="cusetc-btn-cancel" onclick="closePhoneModal()">취소</button>
|
||||
<button class="cusetc-btn-save" onclick="savePhone()">💾 저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- OTC 구매 이력 모달 -->
|
||||
<div class="otc-modal" id="otcModal">
|
||||
<div class="otc-modal-content">
|
||||
@ -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
|
||||
? `<span class="phone-badge has-phone" onclick="event.stopPropagation();openPhoneModal()" title="${phone}">📞 ${phone}</span>`
|
||||
: `<span class="phone-badge no-phone" onclick="event.stopPropagation();openPhoneModal()">📞 전화번호 추가</span>`;
|
||||
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 = `
|
||||
<strong>${currentPrescriptionData.name || '환자'}</strong>
|
||||
<span style="margin-left: 10px; color: #6b7280;">고객코드: ${currentPrescriptionData.cus_code || '-'}</span>
|
||||
`;
|
||||
|
||||
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
|
||||
? `<span class="phone-badge has-phone" onclick="event.stopPropagation();openPhoneModal()" title="${phone}">📞 ${phone}</span>`
|
||||
: `<span class="phone-badge no-phone" onclick="event.stopPropagation();openPhoneModal()">📞 전화번호 추가</span>`;
|
||||
detailInfo.innerHTML =
|
||||
`${currentPrescriptionData.age || '-'}세 / ${currentPrescriptionData.gender || '-'} ${phoneDisplay}`;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// PAAI (Pharmacist Assistant AI) 함수들 - 비동기 토스트 방식
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
Loading…
Reference in New Issue
Block a user