feat: Rx 사용량 페이지에 도매상 잔고 조회 버튼 추가
- 💰 도매상 잔고 버튼 (검색 바 옆)
- 모달로 백제/지오영/수인 3개 도매상 잔고 표시
- 총 미수금 합계 표시
- 새로고침 기능
This commit is contained in:
parent
1829c3efa7
commit
2d09f139ca
@ -727,6 +727,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button class="search-btn" onclick="loadUsageData()">🔍 조회</button>
|
<button class="search-btn" onclick="loadUsageData()">🔍 조회</button>
|
||||||
|
<button class="search-btn" style="background: linear-gradient(135deg, #a855f7, #7c3aed);" onclick="openBalanceModal()">💰 도매상 잔고</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 통계 -->
|
<!-- 통계 -->
|
||||||
@ -2151,5 +2152,205 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 잔고 조회 모달 -->
|
||||||
|
<div class="order-modal" id="balanceModal">
|
||||||
|
<div class="order-modal-content" style="max-width:500px;">
|
||||||
|
<div class="order-modal-header" style="background:linear-gradient(135deg, #7c3aed, #a855f7);">
|
||||||
|
<h3>💰 도매상 잔고 현황</h3>
|
||||||
|
<button class="order-close" onclick="closeBalanceModal()">✕</button>
|
||||||
|
</div>
|
||||||
|
<div class="order-modal-body" id="balanceContent">
|
||||||
|
<div class="loading-state">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<div>잔고 조회 중...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="order-modal-footer">
|
||||||
|
<button class="btn-order-test" onclick="loadBalances()">🔄 새로고침</button>
|
||||||
|
<button class="btn-order-real" onclick="closeBalanceModal()">닫기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 잔고 모달 스타일 */
|
||||||
|
.balance-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.balance-card {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.balance-card.loading {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
.balance-card.error {
|
||||||
|
border-color: var(--accent-rose);
|
||||||
|
background: rgba(244, 63, 94, 0.1);
|
||||||
|
}
|
||||||
|
.balance-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 24px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.balance-icon.baekje { background: linear-gradient(135deg, #d97706, #f59e0b); }
|
||||||
|
.balance-icon.geoyoung { background: linear-gradient(135deg, #0891b2, #06b6d4); }
|
||||||
|
.balance-icon.sooin { background: linear-gradient(135deg, #7c3aed, #a855f7); }
|
||||||
|
|
||||||
|
.balance-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.balance-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.balance-detail {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
.balance-amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.balance-value {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
}
|
||||||
|
.balance-value.baekje { color: #f59e0b; }
|
||||||
|
.balance-value.geoyoung { color: #06b6d4; }
|
||||||
|
.balance-value.sooin { color: #a855f7; }
|
||||||
|
|
||||||
|
.balance-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
.balance-total {
|
||||||
|
background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(6, 182, 212, 0.1));
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.balance-total-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.balance-total-value {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
background: linear-gradient(135deg, #a855f7, #06b6d4);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
.balance-updated {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// ──────────────── 잔고 조회 ────────────────
|
||||||
|
function openBalanceModal() {
|
||||||
|
document.getElementById('balanceModal').classList.add('show');
|
||||||
|
loadBalances();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeBalanceModal() {
|
||||||
|
document.getElementById('balanceModal').classList.remove('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadBalances() {
|
||||||
|
const content = document.getElementById('balanceContent');
|
||||||
|
content.innerHTML = `
|
||||||
|
<div class="loading-state">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<div>잔고 조회 중...</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
const wholesalers = [
|
||||||
|
{ id: 'baekje', name: '백제약품', icon: '💉', api: '/api/baekje/balance' },
|
||||||
|
{ id: 'geoyoung', name: '지오영', icon: '🏭', api: '/api/geoyoung/balance' },
|
||||||
|
{ id: 'sooin', name: '수인약품', icon: '💊', api: '/api/sooin/balance' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const results = {};
|
||||||
|
let totalBalance = 0;
|
||||||
|
|
||||||
|
// 병렬로 조회
|
||||||
|
await Promise.all(wholesalers.map(async (ws) => {
|
||||||
|
try {
|
||||||
|
const resp = await fetch(ws.api, { timeout: 30000 });
|
||||||
|
const data = await resp.json();
|
||||||
|
results[ws.id] = data;
|
||||||
|
if (data.success && data.balance) {
|
||||||
|
totalBalance += data.balance;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
results[ws.id] = { success: false, error: err.message };
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 결과 렌더링
|
||||||
|
let html = '<div class="balance-grid">';
|
||||||
|
|
||||||
|
wholesalers.forEach(ws => {
|
||||||
|
const data = results[ws.id];
|
||||||
|
const isError = !data.success;
|
||||||
|
const balance = data.balance || 0;
|
||||||
|
const prevBalance = data.prev_balance || data.prev_month_balance || 0;
|
||||||
|
|
||||||
|
html += `
|
||||||
|
<div class="balance-card ${isError ? 'error' : ''}">
|
||||||
|
<div class="balance-icon ${ws.id}">${ws.icon}</div>
|
||||||
|
<div class="balance-info">
|
||||||
|
<div class="balance-name">${ws.name}</div>
|
||||||
|
<div class="balance-detail">
|
||||||
|
${isError
|
||||||
|
? `❌ ${data.error || '조회 실패'}`
|
||||||
|
: `전월/전일: ${prevBalance.toLocaleString()}원`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="balance-amount">
|
||||||
|
<div class="balance-value ${ws.id}">
|
||||||
|
${isError ? '-' : balance.toLocaleString()}
|
||||||
|
</div>
|
||||||
|
<div class="balance-label">현재 잔고</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += `
|
||||||
|
<div class="balance-total">
|
||||||
|
<div class="balance-total-label">총 미수금</div>
|
||||||
|
<div class="balance-total-value">${totalBalance.toLocaleString()}원</div>
|
||||||
|
</div>
|
||||||
|
<div class="balance-updated">🕐 ${new Date().toLocaleString('ko-KR')}</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
content.innerHTML = html;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user