a3a1d3fbad
.rv-row 에 grid-template-columns:repeat(6,1fr) !important 로 6열 강제(인쇄 시 3열로 덮이던 문제 차단). height:210mm 고정 제거 → height:auto + 칸 min-height:50mm 로 프린터 기본여백 더해져도 면이 한 장 넘던 문제 해소. rv-side flex 해제해 자연 높이로 흐름. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
292 lines
15 KiB
HTML
292 lines
15 KiB
HTML
{% extends "erp_base.html" %}
|
|
|
|
{% block head_extra %}
|
|
<style>
|
|
.rv-board { display:flex; flex-direction:column; gap:18px; }
|
|
.rv-side { width:100%; }
|
|
.rv-side h3 { text-align:center; margin:0 0 8px; }
|
|
.rv-row { display:grid; grid-template-columns:repeat(6, 1fr); gap:6px; margin-bottom:6px; }
|
|
.rv-cell {
|
|
border:1px solid #cbd5e1; border-radius:6px; padding:7px;
|
|
background:#f8fafc; min-height:104px; display:flex; flex-direction:column; min-width:0;
|
|
cursor:grab; transition:box-shadow .12s, border-color .12s, background .12s;
|
|
}
|
|
.rv-cell.is-empty { background:#fff; }
|
|
.rv-cell.is-selected { border-color:#2563eb; box-shadow:0 0 0 2px #93c5fd inset; background:#eff6ff; }
|
|
.rv-cell.is-dragover { border-color:#2563eb; background:#dbeafe; }
|
|
.rv-cell.dragging { opacity:.45; }
|
|
.rv-cell-head {
|
|
display:flex; align-items:center; justify-content:space-between;
|
|
font-size:14px; font-weight:700; color:#475569; margin-bottom:5px;
|
|
border-bottom:1px solid #e2e8f0; padding-bottom:4px;
|
|
}
|
|
.rv-cell-head .rv-pick {
|
|
flex:0 0 auto; width:16px; height:16px; margin:0; cursor:pointer;
|
|
}
|
|
.rv-items { display:flex; flex-direction:column; gap:4px; }
|
|
.rv-item { font-size:14px; line-height:1.3; }
|
|
.rv-item .rv-name { font-weight:700; color:#0f172a; }
|
|
.rv-item .rv-calc { color:#475569; }
|
|
.rv-item .rv-qty { color:#2563eb; font-weight:700; }
|
|
.rv-empty-note { font-size:13px; color:#cbd5e1; }
|
|
|
|
/* 수정됨 표시: 저장 버튼을 빨강으로 강조 */
|
|
#rv-save-btn.is-dirty {
|
|
background:#dc2626 !important; border-color:#dc2626 !important; color:#fff !important;
|
|
}
|
|
#rv-save-btn.is-dirty:hover { background:#b91c1c !important; border-color:#b91c1c !important; }
|
|
|
|
/* ── 인쇄 미리보기 모달 ── */
|
|
.rvp-overlay {
|
|
display:none; position:fixed; inset:0; z-index:2000;
|
|
background:rgba(15,23,42,.55); overflow:auto; padding:24px;
|
|
}
|
|
.rvp-overlay.is-open { display:block; }
|
|
.rvp-toolbar {
|
|
position:sticky; top:0; display:flex; gap:8px; justify-content:flex-end;
|
|
align-items:center; margin-bottom:16px;
|
|
}
|
|
.rvp-toolbar .rvp-title { margin-right:auto; color:#fff; font-weight:700; font-size:16px; }
|
|
.rvp-pages { display:flex; flex-direction:column; gap:18px; align-items:center; }
|
|
/* 화면 미리보기: A4 가로 비율(297:210) 시트 — 여백 최소, 글자 최대 */
|
|
.rvp-sheet {
|
|
background:#fff; width:min(100%, 1000px); aspect-ratio:297/210;
|
|
box-shadow:0 8px 24px rgba(0,0,0,.3); border-radius:4px;
|
|
display:flex; flex-direction:column; padding:1.5%; box-sizing:border-box;
|
|
}
|
|
.rvp-list { flex:1 1 auto; display:flex; flex-direction:column; justify-content:center; gap:4%; }
|
|
.rvp-line { display:flex; flex-direction:column; align-items:center; text-align:center; gap:0.5%; }
|
|
.rvp-line .rvp-name { font-weight:900; font-size:7vmin; color:#0f172a; line-height:1.05; }
|
|
.rvp-line .rvp-size { font-weight:900; font-size:14vmin; color:#0f172a; line-height:1; }
|
|
.rvp-line .rvp-calc { font-weight:800; font-size:6vmin; color:#1e293b; margin-top:1.5%; }
|
|
.rvp-line .rvp-calc .rvp-box { font-size:9.5vmin; font-weight:900; }
|
|
.rvp-empty { text-align:center; font-weight:900; font-size:9vmin; color:#94a3b8; margin:auto 0; }
|
|
|
|
/* ── 실제 인쇄 ── */
|
|
@media print {
|
|
/* 가로 인쇄: 상하 여백(=프린터 좌우)을 0으로, 좌우만 4mm 유지해 세로 공간 최대 확보 */
|
|
@page { size: A4 landscape; margin: 0 4mm; }
|
|
/* 비인쇄 요소는 display:none 으로 공간까지 제거 — visibility:hidden 은
|
|
공간이 남아 overlay(static)가 아래로 밀려 1페이지가 비던 문제 방지. */
|
|
.erp-sidebar, .erp-topbar { display:none !important; }
|
|
/* 앱 셸이 height:100vh + overflow:hidden 으로 한 화면만 보이게 잘라서,
|
|
인쇄 시 둘째 칸부터 잘려 1장만 나오던 문제. 인쇄에선 조상들의
|
|
높이·오버플로 제한을 풀어 모든 칸(sheet)이 흐르게 한다. */
|
|
html, body.erp-app-body, .erp-app, .erp-content, .erp-page, .mys {
|
|
height:auto !important; min-height:0 !important; max-height:none !important;
|
|
overflow:visible !important;
|
|
}
|
|
.erp-content { margin:0 !important; }
|
|
.erp-page { padding:0 !important; }
|
|
body.printing-cells .mys > *:not(.rvp-overlay) { display:none !important; }
|
|
body.printing-cells .rvp-overlay {
|
|
display:block !important; position:static !important; padding:0 !important;
|
|
background:#fff !important; overflow:visible !important;
|
|
}
|
|
.rvp-toolbar { display:none !important; }
|
|
/* flex 컨테이너면 Chrome이 자식의 page-break를 무시해 여러 칸이 한 장에
|
|
뭉쳐 잘림. block 으로 바꿔 칸(파렛트)마다 한 장씩 끊어 인쇄. */
|
|
.rvp-pages { display:block !important; gap:0 !important; }
|
|
.rvp-sheet {
|
|
width:100% !important; height:100vh !important; aspect-ratio:auto !important;
|
|
box-shadow:none !important; border-radius:0 !important;
|
|
padding:2mm !important;
|
|
/* break-before 가 Chrome에서 더 안정적: 첫 칸 제외 매 칸을 새 장으로. */
|
|
break-before:page; page-break-before:always;
|
|
}
|
|
.rvp-sheet:first-child { break-before:auto; page-break-before:auto; }
|
|
/* 인쇄 시 글씨 더 크게(멀리서도 보이게) — cm 기준.
|
|
칸에 상품이 1개일 때 기준. 2개·3개 이상이면 한 장에 다 들어가도록 단계 축소. */
|
|
.rvp-line .rvp-name { font-size:2.6cm; }
|
|
.rvp-line .rvp-size { font-size:5.5cm; }
|
|
.rvp-line .rvp-calc { font-size:1.8cm; }
|
|
.rvp-line .rvp-calc .rvp-box { font-size:3cm; }
|
|
.rvp-empty { font-size:3cm; }
|
|
/* 상품 2개: 절반 가량으로 축소(2개 합쳐도 A4 가로 1장에 맞게) */
|
|
.rvp-sheet.rvp-multi .rvp-line .rvp-name { font-size:1.5cm; }
|
|
.rvp-sheet.rvp-multi .rvp-line .rvp-size { font-size:3.1cm; }
|
|
.rvp-sheet.rvp-multi .rvp-line .rvp-calc { font-size:1.05cm; }
|
|
.rvp-sheet.rvp-multi .rvp-line .rvp-calc .rvp-box { font-size:1.7cm; }
|
|
/* 상품 3개 이상: 더 작게 */
|
|
.rvp-sheet.rvp-many .rvp-line .rvp-name { font-size:1cm; }
|
|
.rvp-sheet.rvp-many .rvp-line .rvp-size { font-size:2cm; }
|
|
.rvp-sheet.rvp-many .rvp-line .rvp-calc { font-size:0.75cm; }
|
|
.rvp-sheet.rvp-many .rvp-line .rvp-calc .rvp-box { font-size:1.2cm; }
|
|
}
|
|
|
|
/* ── 창고 POG (전체 도면 A4 가로 1장) ── */
|
|
.pog-overlay {
|
|
display:none; position:fixed; inset:0; z-index:2000;
|
|
background:rgba(15,23,42,.55); overflow:auto; padding:24px;
|
|
}
|
|
.pog-overlay.is-open { display:block; }
|
|
.pog-toolbar {
|
|
position:sticky; top:0; display:flex; gap:8px; justify-content:flex-end;
|
|
align-items:center; margin-bottom:16px;
|
|
}
|
|
.pog-toolbar .pog-title { margin-right:auto; color:#fff; font-weight:700; font-size:16px; }
|
|
.pog-pages { display:flex; flex-direction:column; gap:18px; align-items:center; }
|
|
/* A4 가로(297:210) 시트 — 면(Side A/B/Ground)마다 1장.
|
|
container-type:size → 자식이 cqh/cqw 로 시트 크기에 맞춰 확대/축소 */
|
|
.pog-sheet {
|
|
background:#fff; width:min(100%, 1180px); aspect-ratio:297/210;
|
|
box-shadow:0 8px 24px rgba(0,0,0,.3); border-radius:4px;
|
|
padding:1.8cqh 1.4cqw; box-sizing:border-box;
|
|
display:flex; flex-direction:column; overflow:hidden;
|
|
container-type:size;
|
|
}
|
|
.pog-sheet .pog-sheet-head {
|
|
display:flex; justify-content:space-between; align-items:baseline;
|
|
font-weight:800; color:#0f172a; margin-bottom:1.2cqh; flex:0 0 auto;
|
|
}
|
|
.pog-sheet .pog-sheet-head .pog-t { font-size:2.8cqh; }
|
|
.pog-sheet .pog-sheet-head .pog-meta { font-size:1.7cqh; color:#475569; font-weight:600; }
|
|
/* 면 1개가 시트 높이를 꽉 채운다(행 flex 균등 분배 → 칸 커짐) */
|
|
.pog-sheet .rv-side { flex:1 1 auto; display:flex; flex-direction:column; min-height:0; }
|
|
.pog-sheet .rv-side h3 { display:none; }
|
|
.pog-sheet .rv-row { flex:1 1 0; gap:1cqw; margin:0 0 1cqh; min-height:0; }
|
|
.pog-sheet .rv-row:last-child { margin-bottom:0; }
|
|
.pog-sheet .rv-cell {
|
|
height:auto; min-height:0; padding:0.7cqh 0.8cqw; border-radius:4px;
|
|
cursor:default; overflow:hidden; background:#f8fafc; justify-content:flex-start;
|
|
}
|
|
.pog-sheet .rv-cell.is-empty { background:#fff; }
|
|
.pog-sheet .rv-cell-head {
|
|
font-size:1.55cqh; font-weight:800; margin-bottom:0.5cqh; padding-bottom:0.35cqh;
|
|
}
|
|
.pog-sheet .rv-pick { display:none !important; }
|
|
.pog-sheet .rv-items { gap:0.4cqh; }
|
|
.pog-sheet .rv-item { font-size:1.55cqh; line-height:1.25; }
|
|
.pog-sheet .rv-empty-note { font-size:1.55cqh; }
|
|
|
|
@media print {
|
|
body.printing-pog .erp-sidebar, body.printing-pog .erp-topbar { display:none !important; }
|
|
body.printing-pog .mys > *:not(.pog-overlay) { display:none !important; }
|
|
body.printing-pog .pog-overlay {
|
|
display:block !important; position:static !important; padding:0 !important;
|
|
background:#fff !important; overflow:visible !important;
|
|
}
|
|
body.printing-pog .pog-toolbar { display:none !important; }
|
|
body.printing-pog .pog-pages { display:block !important; }
|
|
/* 면(시트)마다 한 장(A4 가로). container-type:size 가 인쇄 시 자식 grid 를
|
|
깨는 Chrome 버그 회피 → containment 해제하고 글자/여백은 mm 로 고정.
|
|
(화면 미리보기는 위쪽 cqh 그대로 사용) */
|
|
body.printing-pog .pog-sheet {
|
|
container-type:normal !important;
|
|
width:100% !important; height:auto !important; aspect-ratio:auto !important;
|
|
padding:4mm 4mm !important;
|
|
box-shadow:none !important; border-radius:0 !important;
|
|
break-before:page; page-break-before:always; page-break-inside:avoid;
|
|
}
|
|
body.printing-pog .pog-sheet:first-child { break-before:auto; page-break-before:auto; }
|
|
/* 면 자연 높이로 흐르게(flex 해제) → 프린터 여백 변동에도 한 면=한 장 */
|
|
body.printing-pog .pog-sheet .rv-side { display:block !important; flex:none !important; }
|
|
/* 6열 강제(인쇄에서 3열로 덮이는 문제 차단) */
|
|
body.printing-pog .pog-sheet .rv-row {
|
|
display:grid !important; grid-template-columns:repeat(6, 1fr) !important;
|
|
gap:2mm !important; margin:0 0 2mm !important;
|
|
}
|
|
body.printing-pog .pog-sheet .pog-sheet-head { margin-bottom:4mm !important; }
|
|
body.printing-pog .pog-sheet .pog-sheet-head .pog-t { font-size:8mm !important; }
|
|
body.printing-pog .pog-sheet .pog-sheet-head .pog-meta { font-size:4.5mm !important; }
|
|
body.printing-pog .pog-sheet .rv-cell {
|
|
min-height:50mm !important; height:auto !important; padding:1.5mm 2mm !important;
|
|
}
|
|
body.printing-pog .pog-sheet .rv-cell-head {
|
|
font-size:3.6mm !important; margin-bottom:1mm !important; padding-bottom:0.8mm !important;
|
|
}
|
|
body.printing-pog .pog-sheet .rv-items { gap:1mm !important; }
|
|
body.printing-pog .pog-sheet .rv-item { font-size:3.6mm !important; }
|
|
body.printing-pog .pog-sheet .rv-empty-note { font-size:3.6mm !important; }
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<section class="mys mys-compact">
|
|
{% include "malaysia/_i18n.html" %}
|
|
{% set active_tab = 'rack' %}
|
|
{% include "malaysia/_nav.html" %}
|
|
|
|
<div class="erp-card">
|
|
<div class="cpg-card-head" style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px;">
|
|
<h2>창고 랙 보기</h2>
|
|
<span class="erp-muted">
|
|
{% if stocktake %}
|
|
<span class="i18n">기준 재고조사</span>: #{{ stocktake.id }} · {{ stocktake.stocktake_date }}
|
|
{% if stocktake.status=='finalized' %}<span class="erp-badge erp-badge-success">확정</span>
|
|
{% elif stocktake.status=='cancelled' %}<span class="erp-badge erp-badge-neutral">취소</span>
|
|
{% else %}<span class="erp-badge erp-badge-inverse">작성중</span>{% endif %}
|
|
{% else %}
|
|
<span class="i18n">표시할 재고조사가 없습니다.</span>
|
|
{% endif %}
|
|
</span>
|
|
</div>
|
|
|
|
{% if stocktake %}
|
|
<div class="erp-page-actions" style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
|
|
<span class="erp-muted i18n" style="flex:1 1 auto;min-width:0;">칸을 드래그해 다른 칸으로 옮기면 구성이 이동(채워진 칸끼리는 맞교환)됩니다. 칸 번호는 그대로입니다. 인쇄할 칸은 체크 후 인쇄하세요.</span>
|
|
<a href="/malaysia/rack/export?wh={{ selected_wh }}" class="erp-btn erp-btn-outline">다운로드</a>
|
|
<button type="button" id="rv-print-btn" class="erp-btn erp-btn-outline">인쇄 미리보기</button>
|
|
<button type="button" id="rv-pog-btn" class="erp-btn erp-btn-outline">창고POG 출력</button>
|
|
<button type="button" id="rv-save-btn" class="erp-btn erp-btn-primary">저장</button>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<form id="rv-save-form" method="post" action="/malaysia/rack/save" style="display:none;">
|
|
<input type="hidden" name="warehouse_code" value="{{ selected_wh }}" />
|
|
<div id="rv-save-fields"></div>
|
|
</form>
|
|
|
|
<div class="rv-board" id="rv-board" style="margin-top:10px;"
|
|
data-wh="{{ selected_wh }}"
|
|
data-stocktake="{% if stocktake %}#{{ stocktake.id }} · {{ stocktake.stocktake_date }}{% endif %}">
|
|
{% for side in rack_layout %}
|
|
<div class="rv-side">
|
|
<h3>{{ side.label }}</h3>
|
|
{% for row in side.rows %}
|
|
<div class="rv-row">
|
|
{% for col in row.cols %}
|
|
{% for cell in col %}
|
|
{% set entries = rack_by_cell.get(cell, []) %}
|
|
<div class="rv-cell {% if not entries %}is-empty{% endif %}"
|
|
data-cell="{{ cell }}" draggable="true"
|
|
data-entries='[{% for e in entries %}{"sku":"{{ e.sku_code }}","ko":{{ (ko_names.get(e.sku_code, e.item_name)) | tojson }},"en":{{ e.item_name | tojson }},"upb":{{ e.units_per_box }},"box":{{ e.box_count }}}{% if not loop.last %},{% endif %}{% endfor %}]'>
|
|
<div class="rv-cell-head">
|
|
<span class="rv-code">{{ cell }}</span>
|
|
<input type="checkbox" class="rv-pick" title="인쇄 선택" draggable="false" />
|
|
</div>
|
|
<div class="rv-items"><!-- JS 렌더 --></div>
|
|
</div>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 인쇄 미리보기 모달 -->
|
|
<div class="rvp-overlay" id="rvp-overlay">
|
|
<div class="rvp-toolbar">
|
|
<span class="rvp-title i18n">인쇄 미리보기</span>
|
|
<button type="button" id="rvp-print" class="erp-btn erp-btn-primary">인쇄</button>
|
|
<button type="button" id="rvp-close" class="erp-btn erp-btn-outline">닫기</button>
|
|
</div>
|
|
<div class="rvp-pages" id="rvp-pages"></div>
|
|
</div>
|
|
|
|
<!-- 창고 POG 미리보기 모달 (전체 도면 1장) -->
|
|
<div class="pog-overlay" id="pog-overlay">
|
|
<div class="pog-toolbar">
|
|
<span class="pog-title i18n">창고 POG 미리보기</span>
|
|
<button type="button" id="pog-print" class="erp-btn erp-btn-primary">인쇄</button>
|
|
<button type="button" id="pog-close" class="erp-btn erp-btn-outline">닫기</button>
|
|
</div>
|
|
<div class="pog-pages" id="pog-pages"></div>
|
|
</div>
|
|
</section>
|
|
<script src="/static/malaysia_rack_view.js?v=20260619c"></script>
|
|
{% endblock %}
|