feat(pmr): 환자 전화번호 표시/수정 기능 추가

- API: 처방 조회 시 CD_PERSON.PHONE 반환
- API: PUT /api/members/{code}/phone - 전화번호 저장
- UI: 나이/성별 옆에 전화번호 뱃지 표시
- UI: 전화번호 없으면 '전화번호 추가' 클릭 가능
- UI: 클릭 시 모달에서 전화번호 입력/저장
This commit is contained in:
thug0bin
2026-03-11 23:42:13 +09:00
parent 4c033b0584
commit e254c5c23d
3 changed files with 172 additions and 9 deletions

View File

@@ -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) 함수들 - 비동기 토스트 방식
// ─────────────────────────────────────────────────────────────