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%; }
|
.filter-group select, .filter-group input { width: 100%; }
|
||||||
.urgency-tabs { flex-wrap: wrap; }
|
.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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -673,6 +805,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 데이터 테이블 -->
|
<!-- 데이터 테이블 -->
|
||||||
|
<div style="margin-bottom: 8px; font-size: 12px; color: var(--text-muted);">
|
||||||
|
💡 행 더블클릭 → 입고이력 확인 (도매상 연락처)
|
||||||
|
</div>
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
<table class="data-table">
|
<table class="data-table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -742,6 +877,34 @@
|
|||||||
<!-- 토스트 -->
|
<!-- 토스트 -->
|
||||||
<div class="toast" id="toast"></div>
|
<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>
|
<script>
|
||||||
let allData = [];
|
let allData = [];
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
@ -869,7 +1032,7 @@
|
|||||||
const hasAmount = item.recoverable_amount && item.recoverable_amount > 0;
|
const hasAmount = item.recoverable_amount && item.recoverable_amount > 0;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<tr class="${urgencyClass}">
|
<tr class="${urgencyClass}" ondblclick="openPurchaseModal('${item.drug_code}', '${escapeHtml(item.drug_name).replace(/'/g, "\\'")}')">
|
||||||
<td>
|
<td>
|
||||||
<span class="urgency-badge ${urgency}">
|
<span class="urgency-badge ${urgency}">
|
||||||
${urgency === 'critical' ? '🔴' : urgency === 'warning' ? '🟠' : '⚪'}
|
${urgency === 'critical' ? '🔴' : urgency === 'warning' ? '🟠' : '⚪'}
|
||||||
@ -891,7 +1054,7 @@
|
|||||||
<td class="date-cell">${formatDate(item.last_purchase_date) || '-'}</td>
|
<td class="date-cell">${formatDate(item.last_purchase_date) || '-'}</td>
|
||||||
<td><span class="status-badge ${item.status}">${getStatusLabel(item.status)}</span></td>
|
<td><span class="status-badge ${item.status}">${getStatusLabel(item.status)}</span></td>
|
||||||
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
@ -1044,6 +1207,67 @@
|
|||||||
toast.className = 'toast show ' + type;
|
toast.className = 'toast show ' + type;
|
||||||
setTimeout(() => { toast.classList.remove('show'); }, 3000);
|
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>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user