6763b2af68
랙 보기에서 칸을 드래그해 다른 칸으로 구성을 옮긴다(채워진 칸끼리 맞교환, Side A↔B 가능). 칸 번호는 유지되고 수량 합계도 불변(위치만). 저장하면 그 배치로 기록되며, 재고조사 '이전값 불러오기'가 이 최종 위치를 불러온다. - db.reposition_rack: 칸(cell_code) 배치만 교체, daily_stocktake_line 보존, 확정본도 허용(취소만 불가). 위치 이동은 전산재고에 영향 없음 - db.previous_rack_entries: 정렬을 랙 저장시각(MAX created_at) 기준으로 통일 → '이전값 불러오기'가 랙 보기 최종 위치와 일치 - POST /malaysia/rack/save: latest_rack_stocktake 대상 reposition - rack_view.html + malaysia_rack_view.js: HTML5 드래그 이동/swap, 칸 체크 선택, 저장(병렬배열 직렬화), 인쇄 미리보기 모달 - 인쇄: 선택한 칸을 칸마다 A4 가로 1장, 굵은 대형 글씨(@media print), 미리보기 후 인쇄 - i18n 항목 추가, malaysia.js 캐시버스트 v20260615c Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
161 lines
7.3 KiB
HTML
161 lines
7.3 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:5px;
|
|
background:#f8fafc; min-height:80px; 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:11px; font-weight:600; color:#475569; margin-bottom:4px;
|
|
border-bottom:1px solid #e2e8f0; padding-bottom:3px;
|
|
}
|
|
.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:3px; }
|
|
.rv-item { font-size:11px; line-height:1.25; }
|
|
.rv-item .rv-name { font-weight:600; color:#0f172a; }
|
|
.rv-item .rv-calc { color:#475569; }
|
|
.rv-item .rv-qty { color:#2563eb; font-weight:600; }
|
|
.rv-empty-note { font-size:11px; color:#cbd5e1; }
|
|
|
|
/* ── 인쇄 미리보기 모달 ── */
|
|
.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:4% 5%; box-sizing:border-box;
|
|
}
|
|
.rvp-cell-code {
|
|
font-weight:900; line-height:1; letter-spacing:.5px;
|
|
font-size:9vmin; color:#0f172a; border-bottom:4px solid #0f172a;
|
|
padding-bottom:2%; margin-bottom:3%; text-align:center;
|
|
}
|
|
.rvp-list { flex:1 1 auto; display:flex; flex-direction:column; justify-content:center; gap:3%; }
|
|
.rvp-line { text-align:center; }
|
|
.rvp-line .rvp-name { display:block; font-weight:900; font-size:6.5vmin; color:#0f172a; line-height:1.1; }
|
|
.rvp-line .rvp-calc { display:block; font-weight:800; font-size:5vmin; color:#1e293b; margin-top:1%; }
|
|
.rvp-empty { text-align:center; font-weight:900; font-size:7vmin; color:#94a3b8; margin:auto 0; }
|
|
|
|
/* ── 실제 인쇄 ── */
|
|
@media print {
|
|
@page { size: A4 landscape; margin: 8mm; }
|
|
body * { visibility: hidden !important; }
|
|
.rvp-overlay, .rvp-overlay * { visibility: visible !important; }
|
|
.rvp-overlay {
|
|
display:block !important; position:static !important; padding:0 !important;
|
|
background:#fff !important; overflow:visible !important;
|
|
}
|
|
.rvp-toolbar { display:none !important; }
|
|
.rvp-pages { gap:0 !important; }
|
|
.rvp-sheet {
|
|
width:100% !important; height:100vh !important; aspect-ratio:auto !important;
|
|
box-shadow:none !important; border-radius:0 !important; page-break-after:always;
|
|
padding:0 !important;
|
|
}
|
|
.rvp-sheet:last-child { page-break-after:auto; }
|
|
/* 인쇄 시 글씨 더 크게(멀리서도 보이게) — cm/vh 기준 */
|
|
.rvp-cell-code { font-size:3cm; border-bottom-width:6px; }
|
|
.rvp-line .rvp-name { font-size:2.4cm; }
|
|
.rvp-line .rvp-calc { font-size:1.6cm; }
|
|
.rvp-empty { font-size:2.5cm; }
|
|
}
|
|
</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>
|
|
<button type="button" id="rv-print-btn" class="erp-btn erp-btn-outline">인쇄 미리보기</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;">
|
|
{% for side in rack_layout %}
|
|
<div class="rv-side">
|
|
<h3>Side {{ side.side }}</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>
|
|
</section>
|
|
<script src="/static/malaysia_rack_view.js?v=20260615a"></script>
|
|
{% endblock %}
|