feat: 환자 처방 내역에서 조제 상세 정보 인라인 펼침 기능 추가

- 환자 처방 내역 모달에서 처방 행 클릭 시 상세 정보 펼침
- 중첩 모달 문제 해결을 위해 인라인 표시 방식으로 변경
- 구성 약재 정보 테이블 표시 (약재명, 보험코드, 첩당용량, 총용량)
- 재고 소비 내역 테이블 표시 (약재명, 원산지, 도매상, 사용량, 단가, 원가)
- 총 원가 자동 계산 및 표시
- chevron 아이콘으로 펼침/접힘 상태 표시
- 다른 행 클릭 시 자동으로 이전 행 닫기

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
시골약사 2026-02-15 12:54:22 +00:00
parent 83f9f10f3d
commit 041d1d81c4
2 changed files with 137 additions and 15 deletions

View File

@ -254,7 +254,7 @@ $(document).ready(function() {
</tr>
`);
} else {
compounds.forEach(compound => {
compounds.forEach((compound, index) => {
// 상태 뱃지
let statusBadge = '';
switch(compound.status) {
@ -271,8 +271,13 @@ $(document).ready(function() {
statusBadge = '<span class="badge bg-secondary">대기</span>';
}
const detailRowId = `compound-detail-${compound.compound_id}`;
tbody.append(`
<tr>
<tr class="compound-row" style="cursor: pointer;" data-compound-id="${compound.compound_id}">
<td>
<i class="bi bi-chevron-right toggle-icon"></i>
</td>
<td>${compound.compound_date || '-'}</td>
<td>${compound.formula_name || '직접조제'}</td>
<td>${compound.je_count || 0}</td>
@ -282,20 +287,59 @@ $(document).ready(function() {
<td>${formatCurrency(compound.sell_price_total || 0)}</td>
<td>${statusBadge}</td>
<td>${compound.prescription_no || '-'}</td>
<td>
<button class="btn btn-sm btn-outline-info view-compound-detail"
data-id="${compound.compound_id}">
<i class="bi bi-eye"></i>
</button>
</tr>
<tr id="${detailRowId}" class="collapse-row" style="display: none;">
<td colspan="10" class="p-0">
<div class="card m-2">
<div class="card-body">
<div class="row">
<div class="col-md-12">
<h6><i class="bi bi-capsule"></i> </h6>
<div id="ingredients-${compound.compound_id}" class="mb-3">
<div class="text-center text-muted">
<div class="spinner-border spinner-border-sm" role="status"></div>
로딩 ...
</div>
</div>
<h6><i class="bi bi-box-seam"></i> </h6>
<div id="consumptions-${compound.compound_id}">
<div class="text-center text-muted">
<div class="spinner-border spinner-border-sm" role="status"></div>
로딩 ...
</div>
</div>
</div>
</div>
</div>
</div>
</td>
</tr>
`);
});
// 상세보기 버튼 이벤트
$('.view-compound-detail').on('click', function() {
const compoundId = $(this).data('id');
viewCompoundDetail(compoundId);
// 행 클릭 이벤트 - 상세 정보 토글
$('.compound-row').on('click', function() {
const compoundId = $(this).data('compound-id');
const detailRow = $(`#compound-detail-${compoundId}`);
const icon = $(this).find('.toggle-icon');
if (detailRow.is(':visible')) {
// 닫기
detailRow.slideUp();
icon.removeClass('bi-chevron-down').addClass('bi-chevron-right');
} else {
// 열기 - 다른 모든 행 닫기
$('.collapse-row').slideUp();
$('.toggle-icon').removeClass('bi-chevron-down').addClass('bi-chevron-right');
// 현재 행 열기
detailRow.slideDown();
icon.removeClass('bi-chevron-right').addClass('bi-chevron-down');
// 상세 정보 로드
loadCompoundDetailInline(compoundId);
}
});
}
@ -311,6 +355,70 @@ $(document).ready(function() {
});
}
// 환자 처방 내역 모달 내에서 조제 상세 정보 로드 (인라인)
function loadCompoundDetailInline(compoundId) {
$.get(`/api/compounds/${compoundId}`, function(response) {
if (response.success && response.data) {
const data = response.data;
// 구성 약재 테이블
let ingredientsHtml = '<table class="table table-sm table-bordered"><thead class="table-light"><tr><th>약재명</th><th>보험코드</th><th>첩당용량</th><th>총용량</th></tr></thead><tbody>';
if (data.ingredients && data.ingredients.length > 0) {
data.ingredients.forEach(ing => {
ingredientsHtml += `
<tr>
<td><strong>${ing.herb_name}</strong></td>
<td>${ing.insurance_code || '-'}</td>
<td>${ing.grams_per_cheop}g</td>
<td>${ing.total_grams}g</td>
</tr>
`;
});
} else {
ingredientsHtml += '<tr><td colspan="4" class="text-center text-muted">약재 정보가 없습니다</td></tr>';
}
ingredientsHtml += '</tbody></table>';
$(`#ingredients-${compoundId}`).html(ingredientsHtml);
// 재고 소비 내역 테이블
let consumptionsHtml = '<table class="table table-sm table-bordered"><thead class="table-light"><tr><th>약재명</th><th>원산지</th><th>도매상</th><th>사용량</th><th>단가</th><th>원가</th></tr></thead><tbody>';
if (data.consumptions && data.consumptions.length > 0) {
let totalCost = 0;
data.consumptions.forEach(con => {
totalCost += con.cost_amount || 0;
consumptionsHtml += `
<tr>
<td><strong>${con.herb_name}</strong></td>
<td>${con.origin_country || '-'}</td>
<td>${con.supplier_name || '-'}</td>
<td>${con.quantity_used}g</td>
<td>${formatCurrency(con.unit_cost_per_g)}/g</td>
<td>${formatCurrency(con.cost_amount)}</td>
</tr>
`;
});
consumptionsHtml += `
<tr class="table-info">
<td colspan="5" class="text-end"><strong> 원가:</strong></td>
<td><strong>${formatCurrency(totalCost)}</strong></td>
</tr>
`;
} else {
consumptionsHtml += '<tr><td colspan="6" class="text-center text-muted">재고 소비 내역이 없습니다</td></tr>';
}
consumptionsHtml += '</tbody></table>';
$(`#consumptions-${compoundId}`).html(consumptionsHtml);
}
}).fail(function() {
$(`#ingredients-${compoundId}`).html('<div class="alert alert-danger">데이터를 불러오는데 실패했습니다.</div>');
$(`#consumptions-${compoundId}`).html('<div class="alert alert-danger">데이터를 불러오는데 실패했습니다.</div>');
});
}
// 처방 목록 로드
function loadFormulas() {
$.get('/api/formulas', function(response) {
@ -847,7 +955,21 @@ $(document).ready(function() {
// 비고
$('#detailNotes').text(data.notes || '');
// 모달 표시
// 부모 모달(환자 처방 내역)을 임시로 숨기고 조제 상세 모달 열기
const parentModal = $('#patientCompoundsModal');
const wasParentOpen = parentModal.hasClass('show');
if (wasParentOpen) {
// 부모 모달 숨기기 (DOM에서 제거하지 않음)
parentModal.modal('hide');
// 조제 상세 모달이 닫힐 때 부모 모달 다시 열기
$('#compoundDetailModal').off('hidden.bs.modal').on('hidden.bs.modal', function() {
parentModal.modal('show');
});
}
// 조제 상세 모달 열기
$('#compoundDetailModal').modal('show');
}
}).fail(function() {

View File

@ -1088,9 +1088,10 @@
<!-- 처방 내역 테이블 -->
<h6><i class="bi bi-list-ul"></i> 처방 내역</h6>
<div class="table-responsive">
<table class="table table-sm table-hover">
<table class="table table-sm">
<thead class="table-dark">
<tr>
<th width="40"></th>
<th width="100">조제일</th>
<th>처방명</th>
<th width="60">제수</th>
@ -1100,11 +1101,10 @@
<th width="100">판매가</th>
<th width="80">상태</th>
<th width="100">처방전번호</th>
<th width="100">작업</th>
</tr>
</thead>
<tbody id="patientCompoundsList">
<!-- Dynamic content -->
<!-- Dynamic content with collapsible details -->
</tbody>
</table>
</div>