feat(반품관리): 약품 더블클릭 시 입고이력 모달 추가
- admin_return_management.html 업데이트: - 입고이력 모달 스타일/HTML 추가 (다크테마 적용) - tr ondblclick → openPurchaseModal() - 도매상 전화번호 클릭 시 복사 기능 - 테이블 위에 더블클릭 힌트 추가 - 상태변경 버튼에 event.stopPropagation() 추가
This commit is contained in:
parent
91f8dea5b4
commit
c71c9ad678
@ -544,6 +544,138 @@
|
||||
.filter-group select, .filter-group input { width: 100%; }
|
||||
.urgency-tabs { flex-wrap: wrap; }
|
||||
}
|
||||
|
||||
/* ══════════════════ 입고이력 모달 ══════════════════ */
|
||||
.purchase-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.8);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1100;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
.purchase-modal.open { display: flex; }
|
||||
.purchase-modal-content {
|
||||
background: var(--bg-card);
|
||||
border-radius: 20px;
|
||||
width: 95%;
|
||||
max-width: 650px;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
|
||||
}
|
||||
.purchase-modal-header {
|
||||
padding: 20px 24px;
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
||||
color: #fff;
|
||||
}
|
||||
.purchase-modal-header h3 {
|
||||
margin: 0 0 6px 0;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.purchase-modal-header .drug-name {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.purchase-modal-body {
|
||||
padding: 16px 24px 24px;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
}
|
||||
.purchase-history-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.purchase-history-table th {
|
||||
background: var(--bg-secondary);
|
||||
padding: 12px 10px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
text-align: left;
|
||||
border-bottom: 2px solid var(--border);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
.purchase-history-table td {
|
||||
padding: 14px 10px;
|
||||
font-size: 13px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.purchase-history-table tr:hover td {
|
||||
background: var(--bg-card-hover);
|
||||
}
|
||||
.supplier-name {
|
||||
font-weight: 600;
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
.supplier-tel {
|
||||
font-size: 12px;
|
||||
color: var(--accent-blue);
|
||||
cursor: pointer;
|
||||
}
|
||||
.supplier-tel:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.purchase-date {
|
||||
color: var(--text-secondary);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
.purchase-qty {
|
||||
font-weight: 600;
|
||||
color: var(--accent-emerald);
|
||||
}
|
||||
.purchase-price {
|
||||
color: var(--accent-gold);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
}
|
||||
.purchase-empty {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.purchase-empty .icon {
|
||||
font-size: 40px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.purchase-modal-footer {
|
||||
padding: 16px 24px;
|
||||
border-top: 1px solid var(--border);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.purchase-modal-btn {
|
||||
padding: 10px 24px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-secondary);
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.purchase-modal-btn:hover {
|
||||
background: var(--bg-card-hover);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
/* 테이블 행 더블클릭 가능 표시 */
|
||||
#dataTableBody tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
#dataTableBody tr:active {
|
||||
background: var(--bg-card-hover) !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -673,6 +805,9 @@
|
||||
</div>
|
||||
|
||||
<!-- 데이터 테이블 -->
|
||||
<div style="margin-bottom: 8px; font-size: 12px; color: var(--text-muted);">
|
||||
💡 행 더블클릭 → 입고이력 확인 (도매상 연락처)
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
@ -742,6 +877,34 @@
|
||||
<!-- 토스트 -->
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<!-- 입고이력 모달 -->
|
||||
<div class="purchase-modal" id="purchaseModal">
|
||||
<div class="purchase-modal-content">
|
||||
<div class="purchase-modal-header">
|
||||
<h3>📦 입고 이력</h3>
|
||||
<div class="drug-name" id="purchaseDrugName">-</div>
|
||||
</div>
|
||||
<div class="purchase-modal-body">
|
||||
<table class="purchase-history-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>도매상</th>
|
||||
<th>입고일</th>
|
||||
<th>수량</th>
|
||||
<th>단가</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="purchaseHistoryBody">
|
||||
<tr><td colspan="4" class="purchase-empty"><div class="icon">📭</div><p>로딩 중...</p></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="purchase-modal-footer">
|
||||
<button class="purchase-modal-btn" onclick="closePurchaseModal()">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let allData = [];
|
||||
let currentPage = 1;
|
||||
@ -869,7 +1032,7 @@
|
||||
const hasAmount = item.recoverable_amount && item.recoverable_amount > 0;
|
||||
|
||||
return `
|
||||
<tr class="${urgencyClass}">
|
||||
<tr class="${urgencyClass}" ondblclick="openPurchaseModal('${item.drug_code}', '${escapeHtml(item.drug_name).replace(/'/g, "\\'")}')">
|
||||
<td>
|
||||
<span class="urgency-badge ${urgency}">
|
||||
${urgency === 'critical' ? '🔴' : urgency === 'warning' ? '🟠' : '⚪'}
|
||||
@ -891,7 +1054,7 @@
|
||||
<td class="date-cell">${formatDate(item.last_purchase_date) || '-'}</td>
|
||||
<td><span class="status-badge ${item.status}">${getStatusLabel(item.status)}</span></td>
|
||||
<td>
|
||||
<button class="action-btn primary" onclick="openStatusModal(${item.id})">상태 변경</button>
|
||||
<button class="action-btn primary" onclick="event.stopPropagation();openStatusModal(${item.id})">상태 변경</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
@ -1044,6 +1207,67 @@
|
||||
toast.className = 'toast show ' + type;
|
||||
setTimeout(() => { toast.classList.remove('show'); }, 3000);
|
||||
}
|
||||
|
||||
// ══════════════════ 입고이력 모달 ══════════════════
|
||||
async function openPurchaseModal(drugCode, drugName) {
|
||||
const modal = document.getElementById('purchaseModal');
|
||||
const nameEl = document.getElementById('purchaseDrugName');
|
||||
const tbody = document.getElementById('purchaseHistoryBody');
|
||||
|
||||
nameEl.textContent = drugName || drugCode;
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="purchase-empty"><div class="icon">⏳</div><p>입고이력 조회 중...</p></td></tr>';
|
||||
modal.classList.add('open');
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/drugs/${drugCode}/purchase-history`);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
if (data.history.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="purchase-empty"><div class="icon">📭</div><p>입고 이력이 없습니다</p></td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = data.history.map(h => `
|
||||
<tr>
|
||||
<td>
|
||||
<div class="supplier-name">${escapeHtml(h.supplier)}</div>
|
||||
${h.supplier_tel ? `<div class="supplier-tel" onclick="event.stopPropagation();copyToClipboard('${h.supplier_tel}')" title="클릭하여 복사">📞 ${h.supplier_tel}</div>` : ''}
|
||||
</td>
|
||||
<td class="purchase-date">${h.date}</td>
|
||||
<td class="purchase-qty">${h.quantity.toLocaleString()}</td>
|
||||
<td class="purchase-price">${h.unit_price ? formatPrice(h.unit_price) : '-'}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
} else {
|
||||
tbody.innerHTML = `<tr><td colspan="4" class="purchase-empty"><div class="icon">⚠️</div><p>조회 실패: ${data.error}</p></td></tr>`;
|
||||
}
|
||||
} catch (err) {
|
||||
tbody.innerHTML = `<tr><td colspan="4" class="purchase-empty"><div class="icon">❌</div><p>오류: ${err.message}</p></td></tr>`;
|
||||
}
|
||||
}
|
||||
|
||||
function closePurchaseModal() {
|
||||
document.getElementById('purchaseModal').classList.remove('open');
|
||||
}
|
||||
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
showToast(`📋 ${text} 복사됨`, 'success');
|
||||
}).catch(() => {
|
||||
const input = document.createElement('input');
|
||||
input.value = text;
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(input);
|
||||
showToast(`📋 ${text} 복사됨`, 'success');
|
||||
});
|
||||
}
|
||||
|
||||
// 모달 외부 클릭 시 닫기
|
||||
document.getElementById('purchaseModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) closePurchaseModal();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user