From eda0429a85fde29f98d031b5b4228092930df320 Mon Sep 17 00:00:00 2001 From: thug0bin Date: Sun, 8 Mar 2026 11:08:02 +0900 Subject: [PATCH] =?UTF-8?q?fix(=EB=B0=98=ED=92=88=EA=B4=80=EB=A6=AC):=20?= =?UTF-8?q?=EC=9D=B8=EC=BD=94=EB=94=A9=20=EC=88=98=EC=A0=95=20(UTF-8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - admin_return_management.html 한글 깨짐 수정 - Python으로 UTF-8 인코딩으로 전체 파일 재작성 - 모든 기능 유지 (입고이력, 위치 컬럼 등) --- .../templates/admin_return_management.html | 780 +++++------------- 1 file changed, 221 insertions(+), 559 deletions(-) diff --git a/backend/templates/admin_return_management.html b/backend/templates/admin_return_management.html index 2b23e12..af04976 100644 --- a/backend/templates/admin_return_management.html +++ b/backend/templates/admin_return_management.html @@ -3,7 +3,7 @@ - 반품 관?- ??국 + 반품 관리 - 청춘약국 @@ -38,7 +38,7 @@ min-height: 100vh; } - /* ?═?═?═?═?═?═?═?═?═ ?더 ?═?═?═?═?═?═?═?═?═ */ + /* ══════════════════ 헤더 ══════════════════ */ .header { background: linear-gradient(135deg, #dc2626 0%, #f97316 50%, #f59e0b 100%); padding: 20px 24px; @@ -89,14 +89,14 @@ background: rgba(255,255,255,0.25); } - /* ?═?═?═?═?═?═?═?═?═ 컨텐??═?═?═?═?═?═?═?═?═ */ + /* ══════════════════ 컨텐츠 ══════════════════ */ .content { max-width: 1800px; margin: 0 auto; padding: 24px; } - /* ?═?═?═?═?═?═?═?═?═ ?계 카드 (2? ?═?═?═?═?═?═?═?═?═ */ + /* ══════════════════ 통계 카드 ══════════════════ */ .stats-row { display: flex; gap: 16px; @@ -129,40 +129,19 @@ .stat-card.purple::before { background: var(--accent-purple); } .stat-card.gold::before { background: var(--accent-gold); } - .stat-icon { - font-size: 20px; - margin-bottom: 8px; - } - .stat-value { - font-size: 24px; - font-weight: 700; - letter-spacing: -1px; - margin-bottom: 2px; - } - .stat-value.small { - font-size: 18px; - } + .stat-icon { font-size: 20px; margin-bottom: 8px; } + .stat-value { font-size: 24px; font-weight: 700; letter-spacing: -1px; margin-bottom: 2px; } + .stat-value.small { font-size: 18px; } .stat-card.rose .stat-value { color: var(--accent-rose); } .stat-card.amber .stat-value { color: var(--accent-amber); } .stat-card.cyan .stat-value { color: var(--accent-cyan); } .stat-card.emerald .stat-value { color: var(--accent-emerald); } .stat-card.purple .stat-value { color: var(--accent-purple); } .stat-card.gold .stat-value { color: var(--accent-gold); } - - .stat-label { - font-size: 11px; - font-weight: 600; - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.5px; - } - .stat-sub { - font-size: 10px; - color: var(--text-muted); - margin-top: 2px; - } + .stat-label { font-size: 11px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; } + .stat-sub { font-size: 10px; color: var(--text-muted); margin-top: 2px; } - /* ?═?═?═?═?═?═?═?═?═ ?터 ??═?═?═?═?═?═?═?═?═ */ + /* ══════════════════ 필터 바 ══════════════════ */ .filter-bar { background: var(--bg-card); border-radius: 16px; @@ -174,18 +153,8 @@ flex-wrap: wrap; align-items: flex-end; } - .filter-group { - display: flex; - flex-direction: column; - gap: 6px; - } - .filter-group label { - font-size: 11px; - font-weight: 600; - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.5px; - } + .filter-group { display: flex; flex-direction: column; gap: 6px; } + .filter-group label { font-size: 11px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; } .filter-group select, .filter-group input { padding: 10px 14px; background: var(--bg-primary); @@ -213,17 +182,10 @@ cursor: pointer; transition: all 0.2s; } - .filter-btn:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4); - } + .filter-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4); } - /* ?═?═?═?═?═?═?═?═?═ 긴급?????═?═?═?═?═?═?═?═?═ */ - .urgency-tabs { - display: flex; - gap: 8px; - margin-bottom: 16px; - } + /* ══════════════════ 긴급도 탭 ══════════════════ */ + .urgency-tabs { display: flex; gap: 8px; margin-bottom: 16px; } .urgency-tab { padding: 10px 20px; border-radius: 10px; @@ -238,35 +200,19 @@ align-items: center; gap: 6px; } - .urgency-tab:hover { - border-color: var(--text-muted); - } - .urgency-tab.active { - background: linear-gradient(135deg, var(--accent-orange), #ea580c); - border-color: transparent; - color: #fff; - } - .urgency-tab .count { - background: rgba(255,255,255,0.2); - padding: 2px 8px; - border-radius: 100px; - font-size: 11px; - } - .urgency-tab.active .count { - background: rgba(255,255,255,0.3); - } + .urgency-tab:hover { border-color: var(--text-muted); } + .urgency-tab.active { background: linear-gradient(135deg, var(--accent-orange), #ea580c); border-color: transparent; color: #fff; } + .urgency-tab .count { background: rgba(255,255,255,0.2); padding: 2px 8px; border-radius: 100px; font-size: 11px; } + .urgency-tab.active .count { background: rgba(255,255,255,0.3); } - /* ?═?═?═?═?═?═?═?═?═ ?이??═?═?═?═?═?═?═?═?═ */ + /* ══════════════════ 테이블 ══════════════════ */ .table-wrap { background: var(--bg-card); border-radius: 16px; border: 1px solid var(--border); overflow: hidden; } - .data-table { - width: 100%; - border-collapse: collapse; - } + .data-table { width: 100%; border-collapse: collapse; } .data-table th { padding: 14px 12px; font-size: 11px; @@ -283,43 +229,18 @@ } .data-table th.center { text-align: center; } .data-table th.right { text-align: right; } - .data-table td { - padding: 12px; - font-size: 13px; - border-bottom: 1px solid rgba(255,255,255,0.05); - vertical-align: middle; - } - .data-table tr:hover { - background: rgba(255,255,255,0.02); - } - .data-table tr.urgent-critical { - background: rgba(244, 63, 94, 0.08); - } - .data-table tr.urgent-warning { - background: rgba(249, 115, 22, 0.05); - } + .data-table td { padding: 12px; font-size: 13px; border-bottom: 1px solid rgba(255,255,255,0.05); vertical-align: middle; } + .data-table tr:hover { background: rgba(255,255,255,0.02); } + .data-table tr.urgent-critical { background: rgba(244, 63, 94, 0.08); } + .data-table tr.urgent-warning { background: rgba(249, 115, 22, 0.05); } - /* ?품 ? */ - .drug-cell { - display: flex; - flex-direction: column; - gap: 2px; - } - .drug-name { - font-weight: 600; - color: var(--text-primary); - font-size: 12px; - } - .drug-code { - font-family: 'JetBrains Mono', monospace; - font-size: 10px; - color: var(--text-muted); - } + /* 약품 셀 */ + .drug-cell { display: flex; flex-direction: column; gap: 2px; } + .drug-name { font-weight: 600; color: var(--text-primary); font-size: 12px; } + .drug-code { font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--text-muted); } - /* ?치 ? */ - .location-cell { - text-align: center; - } + /* 위치 셀 */ + .location-cell { text-align: center; } .location-badge { display: inline-block; background: rgba(251, 191, 36, 0.2); @@ -330,42 +251,16 @@ border-radius: 6px; font-family: 'JetBrains Mono', monospace; } - .location-empty { - color: var(--text-muted); - font-size: 12px; - } + .location-empty { color: var(--text-muted); font-size: 12px; } - /* 긴급??배? */ - .urgency-badge { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 4px 8px; - border-radius: 6px; - font-size: 10px; - font-weight: 600; - } - .urgency-badge.critical { - background: rgba(244, 63, 94, 0.2); - color: var(--accent-rose); - } - .urgency-badge.warning { - background: rgba(249, 115, 22, 0.2); - color: var(--accent-orange); - } - .urgency-badge.normal { - background: rgba(100, 116, 139, 0.2); - color: var(--text-muted); - } + /* 긴급도 배지 */ + .urgency-badge { display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: 6px; font-size: 10px; font-weight: 600; } + .urgency-badge.critical { background: rgba(244, 63, 94, 0.2); color: var(--accent-rose); } + .urgency-badge.warning { background: rgba(249, 115, 22, 0.2); color: var(--accent-orange); } + .urgency-badge.normal { background: rgba(100, 116, 139, 0.2); color: var(--text-muted); } - /* ?태 배? */ - .status-badge { - display: inline-block; - padding: 4px 10px; - border-radius: 6px; - font-size: 11px; - font-weight: 600; - } + /* 상태 배지 */ + .status-badge { display: inline-block; padding: 4px 10px; border-radius: 6px; font-size: 11px; font-weight: 600; } .status-badge.pending { background: rgba(249, 115, 22, 0.2); color: var(--accent-orange); } .status-badge.reviewed { background: rgba(59, 130, 246, 0.2); color: var(--accent-blue); } .status-badge.returned { background: rgba(16, 185, 129, 0.2); color: var(--accent-emerald); } @@ -373,475 +268,243 @@ .status-badge.disposed { background: rgba(244, 63, 94, 0.2); color: var(--accent-rose); } .status-badge.resolved { background: rgba(100, 116, 139, 0.2); color: var(--text-muted); } - /* ?량/?짜/금액 ? */ - .qty-cell { - font-family: 'JetBrains Mono', monospace; - font-weight: 600; - text-align: center; - font-size: 12px; - } - .date-cell { - font-size: 11px; - color: var(--text-secondary); - } - .months-cell { - font-family: 'JetBrains Mono', monospace; - font-weight: 700; - font-size: 12px; - } + /* 수량/날짜/금액 셀 */ + .qty-cell { font-family: 'JetBrains Mono', monospace; font-weight: 600; text-align: center; font-size: 12px; } + .date-cell { font-size: 11px; color: var(--text-secondary); } + .months-cell { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 12px; } .months-cell.critical { color: var(--accent-rose); } .months-cell.warning { color: var(--accent-orange); } .months-cell.normal { color: var(--text-muted); } + .amount-cell { font-family: 'JetBrains Mono', monospace; font-weight: 600; text-align: right; font-size: 12px; color: var(--accent-gold); } + .amount-cell.zero { color: var(--text-muted); } - .amount-cell { - font-family: 'JetBrains Mono', monospace; - font-weight: 600; - text-align: right; - font-size: 12px; - color: var(--accent-gold); - } - .amount-cell.zero { - color: var(--text-muted); - } + /* 액션 버튼 */ + .action-btn { padding: 6px 12px; border: none; border-radius: 6px; font-size: 11px; font-weight: 600; cursor: pointer; transition: all 0.2s; } + .action-btn.primary { background: linear-gradient(135deg, var(--accent-orange), #ea580c); color: #fff; } + .action-btn.primary:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4); } - /* ?션 버튼 */ - .action-btn { - padding: 6px 12px; - border: none; - border-radius: 6px; - font-size: 11px; - font-weight: 600; - cursor: pointer; - transition: all 0.2s; - } - .action-btn.primary { - background: linear-gradient(135deg, var(--accent-orange), #ea580c); - color: #fff; - } - .action-btn.primary:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4); - } - - /* ?═?═?═?═?═?═?═?═?═ ?이지?이???═?═?═?═?═?═?═?═?═ */ - .pagination { - display: flex; - justify-content: center; - align-items: center; - gap: 8px; - padding: 20px; - } - .page-btn { - padding: 8px 14px; - border: 1px solid var(--border); - border-radius: 8px; - background: var(--bg-secondary); - color: var(--text-secondary); - font-size: 13px; - font-weight: 500; - cursor: pointer; - transition: all 0.2s; - } + /* ══════════════════ 페이지네이션 ══════════════════ */ + .pagination { display: flex; justify-content: center; align-items: center; gap: 8px; padding: 20px; } + .page-btn { padding: 8px 14px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-secondary); color: var(--text-secondary); font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s; } .page-btn:hover { border-color: var(--accent-orange); color: var(--accent-orange); } .page-btn.active { background: linear-gradient(135deg, var(--accent-orange), #ea580c); border-color: transparent; color: #fff; } .page-btn:disabled { opacity: 0.3; cursor: not-allowed; } .page-info { color: var(--text-muted); font-size: 13px; } - /* ?═?═?═?═?═?═?═?═?═ 모달 ?═?═?═?═?═?═?═?═?═ */ - .modal-overlay { - position: fixed; - inset: 0; - background: rgba(0,0,0,0.7); - display: none; - align-items: center; - justify-content: center; - z-index: 1000; - } + /* ══════════════════ 모달 ══════════════════ */ + .modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.7); display: none; align-items: center; justify-content: center; z-index: 1000; } .modal-overlay.open { display: flex; } - .modal { - background: var(--bg-card); - border-radius: 20px; - padding: 28px; - width: 90%; - max-width: 500px; - border: 1px solid var(--border); - box-shadow: 0 20px 60px rgba(0,0,0,0.5); - } - .modal-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 24px; - } + .modal { background: var(--bg-card); border-radius: 20px; padding: 28px; width: 90%; max-width: 500px; border: 1px solid var(--border); box-shadow: 0 20px 60px rgba(0,0,0,0.5); } + .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; } .modal-title { font-size: 18px; font-weight: 700; } .modal-close { background: none; border: none; color: var(--text-muted); font-size: 24px; cursor: pointer; } .modal-body { margin-bottom: 24px; } .form-group { margin-bottom: 16px; } .form-group label { display: block; font-size: 12px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px; } - .form-group select, .form-group textarea { - width: 100%; - padding: 12px 16px; - background: var(--bg-primary); - border: 1px solid var(--border); - border-radius: 10px; - font-size: 14px; - font-family: inherit; - color: var(--text-primary); - } + .form-group select, .form-group textarea { width: 100%; padding: 12px 16px; background: var(--bg-primary); border: 1px solid var(--border); border-radius: 10px; font-size: 14px; font-family: inherit; color: var(--text-primary); } .form-group textarea { min-height: 100px; resize: vertical; } .form-group select:focus, .form-group textarea:focus { outline: none; border-color: var(--accent-orange); } .modal-footer { display: flex; justify-content: flex-end; gap: 12px; } - .modal-btn { - padding: 12px 24px; - border-radius: 10px; - font-size: 14px; - font-weight: 600; - cursor: pointer; - transition: all 0.2s; - } + .modal-btn { padding: 12px 24px; border-radius: 10px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s; } .modal-btn.cancel { background: var(--bg-secondary); border: 1px solid var(--border); color: var(--text-secondary); } .modal-btn.submit { background: linear-gradient(135deg, var(--accent-orange), #ea580c); border: none; color: #fff; } .modal-btn.submit:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4); } - .drug-detail { - background: var(--bg-secondary); - border-radius: 12px; - padding: 16px; - margin-bottom: 20px; - } + .drug-detail { background: var(--bg-secondary); border-radius: 12px; padding: 16px; margin-bottom: 20px; } .drug-detail-name { font-size: 16px; font-weight: 700; margin-bottom: 8px; } .drug-detail-info { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; font-size: 13px; } .drug-detail-item { display: flex; justify-content: space-between; } .drug-detail-label { color: var(--text-muted); } .drug-detail-value { font-weight: 600; font-family: 'JetBrains Mono', monospace; } - /* ?═?═?═?═?═?═?═?═?═ 로딩/??태 ?═?═?═?═?═?═?═?═?═ */ + /* ══════════════════ 로딩/빈 상태 ══════════════════ */ .loading-state, .empty-state { text-align: center; padding: 60px 20px; color: var(--text-muted); } - .loading-spinner { - width: 40px; height: 40px; - border: 3px solid var(--border); - border-top-color: var(--accent-orange); - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto 16px; - } + .loading-spinner { width: 40px; height: 40px; border: 3px solid var(--border); border-top-color: var(--accent-orange); border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 16px; } @keyframes spin { to { transform: rotate(360deg); } } .empty-icon { font-size: 48px; margin-bottom: 16px; } - /* ?═?═?═?═?═?═?═?═?═ ?스???═?═?═?═?═?═?═?═?═ */ - .toast { - position: fixed; - bottom: 32px; - left: 50%; - transform: translateX(-50%) translateY(20px); - padding: 14px 28px; - background: var(--bg-card); - border: 1px solid var(--border); - border-radius: 12px; - color: var(--text-primary); - font-size: 14px; - font-weight: 500; - box-shadow: 0 8px 32px rgba(0,0,0,0.3); - opacity: 0; - transition: all 0.3s; - z-index: 300; - } + /* ══════════════════ 토스트 ══════════════════ */ + .toast { position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%) translateY(20px); padding: 14px 28px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px; color: var(--text-primary); font-size: 14px; font-weight: 500; box-shadow: 0 8px 32px rgba(0,0,0,0.3); opacity: 0; transition: all 0.3s; z-index: 300; } .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); } .toast.success { border-color: var(--accent-emerald); } .toast.error { border-color: var(--accent-rose); } - /* ?═?═?═?═?═?═?═?═?═ 반응???═?═?═?═?═?═?═?═?═ */ - @media (max-width: 1200px) { - .stats-row { flex-wrap: wrap; } - .stat-card { min-width: calc(33% - 12px); } - } - @media (max-width: 768px) { - .stat-card { min-width: calc(50% - 8px); } - .header-nav { display: none; } - .filter-bar { flex-direction: column; } - .filter-group { width: 100%; } - .filter-group select, .filter-group input { width: 100%; } - .urgency-tabs { flex-wrap: wrap; } - } + /* ══════════════════ 반응형 ══════════════════ */ + @media (max-width: 1200px) { .stats-row { flex-wrap: wrap; } .stat-card { min-width: calc(33% - 12px); } } + @media (max-width: 768px) { .stat-card { min-width: calc(50% - 8px); } .header-nav { display: none; } .filter-bar { flex-direction: column; } .filter-group { width: 100%; } .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 { 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; - } + .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; }
-

? 반품 ?보 관?/h1> -

?기 미사???약??반품/?기 관?/p> +

📦 반품 후보 관리

+

장기 미사용 의약품 반품/폐기 관리

- +
-
?
+
🔴
-
-
3?? 미사??/div> -
긴급 처리 ?요
+
3년+ 미사용
+
긴급 처리 필요
-
?
+
🟠
-
-
2?? 미사??/div> -
검??권장
+
2년+ 미사용
+
검토 권장
-
?
+
📋
-
-
미결??/div> -
pending ?태
+
미결정
+
pending 상태
-
??/div> +
-
-
처리?료
+
처리완료
-
?
+
📊
-
-
?체 ?보
+
전체 후보
- +
-
?
+
💰
-
-
??수가??금액
-
?체 반품 ???/div> +
회수가능 금액
+
전체 반품 가치
-
??
+
🔴💰
-
-
3?? 금액
-
긴급 ?수 ???/div> +
3년+ 금액
+
긴급 처리 가치
-
??
+
🟠💰
-
-
2?? 금액
-
주의 ???/div> +
2년+ 금액
+
검토 가치
- +
- +
-
- - + +
- +
- +
- +
- +
- ? ???블?릭 ???고?력 ?인 (?매???락? + 💡 행 더블클릭 → 입고이력 확인 (도매상 연락처)
- - - - - - - + + + + + + + + + + @@ -849,7 +512,7 @@ @@ -857,70 +520,70 @@
긴급?품?치?재?/th> - ???수가?금??/th> - 마??처방미사??/th> - 마???고?태?션약품위치현재고단가회수가능금액마지막 처방미사용마지막 입고상태액션
-
?이??로딩 ?..
+
데이터 로딩 중...
- +
- + - +
- +
-

? ?고 ?력

+

📦 입고 이력

-
- - + + + + - +
?매??/th> - ?고??/th> - ?량??도매상입고일수량단가
?

로딩 ?..

📭

로딩 중...

@@ -940,7 +603,7 @@ async function loadData() { const tbody = document.getElementById('dataTableBody'); - tbody.innerHTML = `
?이??로딩 ?..
`; + tbody.innerHTML = `
데이터 로딩 중...
`; const status = document.getElementById('filterStatus').value; const urgency = document.getElementById('filterUrgency').value; @@ -964,10 +627,10 @@ currentPage = 1; renderTable(); } else { - tbody.innerHTML = `
?️
?류: ${data.error}
`; + tbody.innerHTML = `
⚠️
오류: ${data.error}
`; } } catch (err) { - tbody.innerHTML = `
??/div>
?이??로드 ?패
`; + tbody.innerHTML = `
데이터 로드 실패
`; } } @@ -978,23 +641,22 @@ document.getElementById('statProcessed').textContent = stats.processed || 0; document.getElementById('statTotal').textContent = stats.total || 0; - // 금액 ?시 document.getElementById('statTotalAmount').textContent = formatAmount(stats.total_amount || 0); document.getElementById('statCriticalAmount').textContent = formatAmount(stats.critical_amount || 0); document.getElementById('statWarningAmount').textContent = formatAmount(stats.warning_amount || 0); } function formatAmount(amount) { - if (!amount || amount === 0) return '??'; + if (!amount || amount === 0) return '₩0'; if (amount >= 1000000) { - return '?? + (amount / 10000).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + '?; + return '₩' + (amount / 10000).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + '만'; } - return '?? + Math.round(amount).toLocaleString(); + return '₩' + Math.round(amount).toLocaleString(); } function formatPrice(price) { if (!price || price === 0) return '-'; - return '?? + Math.round(price).toLocaleString(); + return '₩' + Math.round(price).toLocaleString(); } function updateTabs() { @@ -1036,7 +698,7 @@ } if (filteredData.length === 0) { - tbody.innerHTML = `
?
?당 조건??반품 ?보가 ?습?다
`; + tbody.innerHTML = `
📦
해당 조건의 반품 후보가 없습니다
`; document.getElementById('pagination').innerHTML = ''; return; } @@ -1055,7 +717,7 @@ - ${urgency === 'critical' ? '?' : urgency === 'warning' ? '?' : '??} + ${urgency === 'critical' ? '🔴' : urgency === 'warning' ? '🟠' : '⚪'} @@ -1067,7 +729,7 @@ ${item.location ? `${escapeHtml(item.location)}` : '-'} ${item.current_stock || 0} ${formatPrice(item.unit_price)} - ${hasAmount ? '?? + Math.round(item.recoverable_amount).toLocaleString() : '-'} + ${hasAmount ? '₩' + Math.round(item.recoverable_amount).toLocaleString() : '-'} ${formatDate(item.last_prescription_date) || '-'} ${item.months_since_use ? item.months_since_use + '개월' : '-'} @@ -1075,7 +737,7 @@ ${formatDate(item.last_purchase_date) || '-'} ${getStatusLabel(item.status)} - `; @@ -1088,12 +750,12 @@ const pagination = document.getElementById('pagination'); if (totalPages <= 1) { - pagination.innerHTML = `?${totalItems}?/span>`; + pagination.innerHTML = `총 ${totalItems}건`; return; } let html = ``; - html += ``; const maxVisible = 5; let startPage = Math.max(1, currentPage - Math.floor(maxVisible / 2)); @@ -1104,9 +766,9 @@ html += ``; } - html += ``; html += ``; - html += `?${totalItems}?/span>`; + html += `총 ${totalItems}건`; pagination.innerHTML = html; } @@ -1127,27 +789,27 @@
${escapeHtml(item.drug_name)}
- ?품코드 + 약품코드 ${item.drug_code}
- ?재?/span> + 현재고 ${item.current_stock || 0}
- ?? + 단가 ${formatPrice(item.unit_price)}
- ?수가?금??/span> - ${hasAmount ? '?? + Math.round(item.recoverable_amount).toLocaleString() : '-'} + 회수가능금액 + ${hasAmount ? '₩' + Math.round(item.recoverable_amount).toLocaleString() : '-'}
- 마??처방 + 마지막 처방 ${formatDate(item.last_prescription_date) || '-'}
- 미사??기간 + 미사용 기간 ${item.months_since_use ? item.months_since_use + '개월' : '-'}
@@ -1170,7 +832,7 @@ const reason = document.getElementById('modalReason').value; if (status === 'keep' && !reason.trim()) { - showToast('보류 ?태?서???유 ?력???수?니??, 'error'); + showToast('보류 상태에서는 사유 입력이 필수입니다', 'error'); return; } @@ -1184,14 +846,14 @@ const data = await res.json(); if (data.success) { - showToast('?태가 변경되?습?다', 'success'); + showToast('상태가 변경되었습니다', 'success'); closeModal(); loadData(); } else { - showToast('변??패: ' + data.error, 'error'); + showToast('변경 실패: ' + data.error, 'error'); } } catch (err) { - showToast('?버 ?류', 'error'); + showToast('서버 오류', 'error'); } } @@ -1212,12 +874,12 @@ function getStatusLabel(status) { const labels = { - 'pending': '미결??, - 'reviewed': '검?됨', - 'returned': '반품?료', + 'pending': '미결정', + 'reviewed': '검토됨', + 'returned': '반품완료', 'keep': '보류', - 'disposed': '?기', - 'resolved': '?고?진' + 'disposed': '폐기', + 'resolved': '재고소진' }; return labels[status] || status; } @@ -1229,14 +891,14 @@ 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 = '
??/div>

?고?력 조회 ?..

'; + tbody.innerHTML = '

입고이력 조회 중...

'; modal.classList.add('open'); try { @@ -1245,13 +907,13 @@ if (data.success) { if (data.history.length === 0) { - tbody.innerHTML = '
?

?고 ?력???습?다

'; + tbody.innerHTML = '
📭

입고 이력이 없습니다

'; } else { tbody.innerHTML = data.history.map(h => `
${escapeHtml(h.supplier)}
- ${h.supplier_tel ? `
? ${h.supplier_tel}
` : ''} + ${h.supplier_tel ? `
📞 ${h.supplier_tel}
` : ''} ${h.date} ${h.quantity.toLocaleString()} @@ -1260,10 +922,10 @@ `).join(''); } } else { - tbody.innerHTML = `
?️

조회 ?패: ${data.error}

`; + tbody.innerHTML = `
⚠️

조회 실패: ${data.error}

`; } } catch (err) { - tbody.innerHTML = `
??/div>

?류: ${err.message}

`; + tbody.innerHTML = `

오류: ${err.message}

`; } } @@ -1273,7 +935,7 @@ function copyToClipboard(text) { navigator.clipboard.writeText(text).then(() => { - showToast(`? ${text} 복사??, 'success'); + showToast(`📋 ${text} 복사됨`, 'success'); }).catch(() => { const input = document.createElement('input'); input.value = text; @@ -1281,14 +943,14 @@ input.select(); document.execCommand('copy'); document.body.removeChild(input); - showToast(`? ${text} 복사??, 'success'); + showToast(`📋 ${text} 복사됨`, 'success'); }); } - // 모달 ?? ?릭 ???기 + // 모달 외부 클릭 시 닫기 document.getElementById('purchaseModal').addEventListener('click', function(e) { if (e.target === this) closePurchaseModal(); }); - + \ No newline at end of file