Files
dbx-main/app/modules/cupang/templates/cupang/index.html
T
king 7d9f7fa364 feat(cupang): 분배 확정 즉시 실행 + 저장 중 스피너
- 출고일자 선택 대화상자 제거. 확정 시 활성 출고일(업로드 F13−1일, 없으면 오늘)로 바로 저장
- 저장 중 스피너 모달 표시 → 응답 오면 닫고 달력으로 이동(여러 날짜면 다음 날짜로 이어감)
- 실패 시 모달 닫고 사유를 상단 메시지로 표시, 버튼 재활성화

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 20:39:25 +09:00

223 lines
8.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260903g" />{% endblock %}
{% block content %}
<section class="cpg">
<!-- 페이지 액션 (달력 컬럼 폭에 맞춤: 신규 좌측 / 설정 달력 오른쪽 끝) -->
<div class="cpg-actions-grid">
<div class="cpg-actions-main">
<a class="erp-btn erp-btn-primary" href="/cupang/box-calc">+ 신규 등록</a>
<span class="cpg-settings-btns">
<a class="erp-btn erp-btn-outline" href="/cupang/products">제품명 설정</a>
<a class="erp-btn erp-btn-outline" href="/cupang/box-rules">상자 입수량 설정</a>
</span>
</div>
<div class="cpg-actions-spacer"></div>
</div>
<div class="cpg-layout">
<!-- ── 왼쪽: 2개월 월간 달력 ── -->
<div class="erp-card cpg-cal-card">
<div class="cpg-mcal-bar">
<div class="cpg-mcal-nav">
<a class="cpg-mcal-navbtn" title="이전 달"
href="/cupang/?year={{ prev_y }}&month={{ prev_m }}"></a>
<a class="cpg-mcal-navbtn" title="다음 달"
href="/cupang/?year={{ next_y }}&month={{ next_m }}"></a>
</div>
<h2 class="cpg-mcal-range">{{ months[0].label }} {{ months[1].label }}</h2>
<a class="cpg-mcal-todaybtn" href="/cupang/">오늘</a>
</div>
<div class="cpg-mcal-months">
{% for m in months %}
<section class="cpg-mcal{% if loop.first %} is-current{% endif %}">
<header class="cpg-mcal-h">
<span class="cpg-mcal-mname">{{ m.month }}월</span>
<span class="cpg-mcal-myear">{{ m.year }}</span>
{% if m.ship_total %}
<span class="cpg-mcal-total">출고 {{ m.ship_total }}건</span>
{% endif %}
</header>
<div class="cpg-mcal-grid">
{% for wd in weekdays %}
<div class="cpg-mcal-wd {% if loop.index0 == 0 %}is-sun{% elif loop.index0 == 6 %}is-sat{% endif %}">{{ wd }}</div>
{% endfor %}
{% for week in m.weeks %}
{% for cell in week %}
<a class="cpg-mcal-cell
{% if not cell.in_month %}is-out{% endif %}
{% if cell.is_today %}is-today{% endif %}
{% if cell.is_selected %}is-selected{% endif %}
{% if cell.counts.ship %}has-ship{% endif %}
{% if cell.is_sunday or cell.is_holiday %}is-red{% elif cell.is_saturday %}is-blue{% endif %}"
href="/cupang/?year={{ year }}&month={{ month }}&date={{ cell.date }}"
title="{{ cell.date }}{% if cell.counts.ship %} — 출고 {{ cell.counts.ship }}건 / 센터 {{ cell.counts.centers }}곳{% endif %}">
<span class="cpg-mcal-day">{{ cell.day }}</span>
{% if cell.counts.ship %}
<span class="cpg-mcal-tag">{{ cell.counts.ship }}건<em>{{ cell.counts.centers }}곳</em></span>
{% endif %}
</a>
{% endfor %}
{% endfor %}
</div>
</section>
{% endfor %}
</div>
<div class="cpg-mcal-legend">
<span><i class="cpg-lg-dot"></i>출고 있는 날</span>
<span><i class="cpg-lg-today"></i>오늘</span>
<span><i class="cpg-lg-sel"></i>선택한 날</span>
</div>
</div>
<!-- ── 오른쪽: 선택일 출고 묶음 리스트 ── -->
<div class="erp-card cpg-list-card">
<div class="cpg-list-head">
<h2>{{ selected_date }} 출고</h2>
<span class="erp-muted">{{ sel_shipments|length }}건</span>
{% if sel_shipments %}
<button type="button" class="erp-btn erp-btn-danger cpg-btn-sm cpg-day-del"
data-day-del="{{ selected_date }}" data-count="{{ sel_shipments|length }}">이 날짜 전체 삭제</button>
{% endif %}
</div>
{% if sel_shipments %}
<ul class="cpg-list">
{% for s in sel_shipments %}
{# ③ 센터 분배 카드와 같은 형식 — 혼합 상자는 내용물까지 펼쳐 보여준다 #}
<li class="cpg-list-item cpg-dist-center has-items">
<div class="cpg-dist-head">
<a class="cpg-ship-name" href="/cupang/{{ s.id }}">{{ s.center_name_snapshot or '센터 미지정' }}</a>
<span class="erp-badge erp-badge-neutral">{{ s.ship_method }}</span>
<span class="cpg-dist-sum">
<span class="erp-badge erp-badge-neutral">{{ s.total_boxes }}상자</span>
<span class="erp-badge erp-badge-neutral">{{ s.total_qty }}개</span>
<button type="button" class="cpg-icon-btn is-danger" title="이 출고 삭제"
data-del="{{ s.id }}" data-name="{{ s.center_name_snapshot }}">삭제</button>
</span>
</div>
<ul class="cpg-dist-items">
{% if s.box_plan %}
{% for e in s.box_plan %}
<li class="cpg-dist-item{% if e.kind == 'mix' %} is-mix{% endif %}">
<div class="cpg-dist-line">
<span class="cpg-dist-name">{{ e.name }}</span>
<span class="cpg-dist-unit">{{ e.count }}상자 · {{ e.quantity }}개</span>
</div>
{% if e.kind == 'mix' and e['items'] %}
<ul class="cpg-dist-tree">
{% for it in e['items'] %}
<li><span class="cpg-tree-name">{{ it.product_name }}</span>
<span class="cpg-tree-qty">{{ it.quantity }}개</span></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
{% else %}
{# 예전에 만든 출고(상자 구성 미저장) — 제품 합계만 표시 #}
{% for it in s['items'] %}
<li class="cpg-dist-item">
<div class="cpg-dist-line">
<span class="cpg-dist-name">{{ it.name }}</span>
<span class="cpg-dist-unit">{{ it.boxes }}상자 · {{ it.qty }}개</span>
</div>
</li>
{% endfor %}
{% endif %}
</ul>
<div class="cpg-ship-meta erp-muted">출고 {{ s.ship_date }} · 센터입고 {{ s.center_arrival_date }}</div>
</li>
{% endfor %}
</ul>
{% else %}
<p class="erp-muted cpg-empty">선택한 날짜의 출고 묶음이 없습니다.
<a href="/cupang/box-calc">상자 계산에서 등록</a></p>
{% endif %}
</div>
</div>
<!-- 삭제 확인 팝업 -->
<div class="cpg-modal" id="cpg-del-dlg" hidden>
<div class="cpg-modal-back" data-del-close></div>
<div class="cpg-modal-box cpg-del-box" role="dialog" aria-modal="true" aria-labelledby="cpg-del-title">
<h3 id="cpg-del-title">출고 삭제</h3>
<p class="cpg-del-msg" id="cpg-del-msg"></p>
<div class="cpg-del-act">
<button type="button" class="erp-btn erp-btn-outline" data-del-close>취소</button>
<button type="button" class="erp-btn erp-btn-danger" id="cpg-del-ok">삭제</button>
</div>
</div>
</div>
<form method="post" id="cpg-del-form" hidden>
<input type="hidden" name="date" id="cpg-del-date" />
<input type="hidden" name="next" id="cpg-del-next" />
</form>
</section>
{% endblock %}
{% block scripts %}
<script>
(function () {
var dlg = document.getElementById("cpg-del-dlg");
if (!dlg) return;
var msgEl = document.getElementById("cpg-del-msg");
var okBtn = document.getElementById("cpg-del-ok");
var form = document.getElementById("cpg-del-form");
var dateEl = document.getElementById("cpg-del-date");
var nextEl = document.getElementById("cpg-del-next");
var pending = null; // {action, date}
function close() { dlg.hidden = true; pending = null; }
function open(message, action, day) {
msgEl.textContent = message;
pending = { action: action, date: day || "" };
dlg.hidden = false;
okBtn.focus();
}
Array.prototype.forEach.call(dlg.querySelectorAll("[data-del-close]"), function (el) {
el.addEventListener("click", close);
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && !dlg.hidden) close();
});
okBtn.addEventListener("click", function () {
if (!pending) return;
form.action = pending.action;
dateEl.value = pending.date;
nextEl.value = window.location.pathname + window.location.search;
form.submit();
});
document.addEventListener("click", function (e) {
var one = e.target.closest("[data-del]");
if (one) {
open('"' + (one.dataset.name || "이 센터") + '" 출고를 삭제할까요?',
"/cupang/" + one.dataset.del + "/delete", "");
return;
}
var day = e.target.closest("[data-day-del]");
if (day) {
open(day.dataset.dayDel + " 출고 " + day.dataset.count + "건을 모두 삭제할까요?",
"/cupang/day-delete", day.dataset.dayDel);
}
});
})();
</script>
{% endblock %}