feat(cupang): 센터에 담긴 혼합 박스 내용물 트리 표시

③ 센터 분배에서 혼합 박스 줄 아래에 무엇이 몇 개 들어가는지 트리로
펼쳐 보여준다. 2박스 이상이면 총 개수와 함께 "(4개 × 2박스)" 를 덧붙인다.
수량을 바꾸면 트리 수치도 즉시 갱신된다. 단일 제품 박스는 트리가 없다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 03:42:39 +09:00
parent 87b49abb71
commit c9a16d8cc4
9 changed files with 64 additions and 11 deletions
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829h" />{% endblock %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829i" />{% endblock %}
{% block content %}
<section class="cpg">
@@ -173,6 +173,7 @@
// ── 상태 ─────────────────────────────────────────
var calc = { results: [], mixes: [] }; // 서버 계산 결과
var units = {}; // key -> 박스 1개당 상품 수
var contents = {}; // key -> 혼합 박스 내용물 [{product_name, quantity}]
var labels = {}; // key -> 표시 이름
var openCenters = []; // ③ 에 추가한 센터 id (문자열)
var alloc = {}; // centerId -> [{id, key, count}]
@@ -230,6 +231,7 @@
calc.mixes = (data && data.mixes) || [];
units = {};
labels = {};
contents = {};
calc.results.forEach(function (r) {
units[prodKey(r.product_code)] = r.units_per_box;
labels[prodKey(r.product_code)] = r.product_name;
@@ -240,6 +242,9 @@
b.items.forEach(function (it) { n += it.quantity; });
units[mixKey(m.box_name, i)] = n;
labels[mixKey(m.box_name, i)] = m.box_name + " 혼합 #" + (i + 1);
contents[mixKey(m.box_name, i)] = b.items.map(function (it) {
return { product_name: it.product_name, quantity: it.quantity };
});
});
});
var had = Object.keys(alloc).some(function (k) { return alloc[k].length; });
@@ -388,6 +393,18 @@
}
}
// 혼합 박스는 안에 무엇이 몇 개 들어가는지 트리로 펼쳐 보여준다.
function treeHtml(entry) {
var list = contents[entry.key];
if (!list || !list.length) return "";
return '<ul class="cpg-dist-tree">' + list.map(function (it) {
return '<li><span class="cpg-tree-name">' + esc(it.product_name) + "</span>" +
'<span class="cpg-tree-qty">' + (it.quantity * entry.count) + "개</span>" +
(entry.count > 1 ? '<span class="cpg-tree-per">(' + it.quantity + "개 × " + entry.count + "박스)</span>" : "") +
"</li>";
}).join("") + "</ul>";
}
// ── ③ 센터 분배 렌더 ──────────────────────────────
function renderDist() {
if (!distList) return;
@@ -402,10 +419,13 @@
boxes += a.count;
pieces += a.count * per;
items += '<li class="cpg-dist-item" data-entry="' + a.id + '">' +
'<span class="cpg-dist-name">' + esc(labels[a.key] || a.key) + "</span>" +
'<input class="erp-input cpg-dist-qty" type="number" min="1" step="1" value="' + a.count + '" />' +
'<span class="cpg-dist-unit">박스 · ' + (a.count * per) + "개</span>" +
'<button type="button" class="erp-btn erp-btn-danger cpg-dist-del" title="빼기" aria-label="빼기">✕</button>' +
'<div class="cpg-dist-line">' +
'<span class="cpg-dist-name">' + esc(labels[a.key] || a.key) + "</span>" +
'<input class="erp-input cpg-dist-qty" type="number" min="1" step="1" value="' + a.count + '" />' +
'<span class="cpg-dist-unit">박스 · ' + (a.count * per) + "개</span>" +
'<button type="button" class="erp-btn erp-btn-danger cpg-dist-del" title="빼기" aria-label="빼기">✕</button>' +
"</div>" +
treeHtml(a) +
"</li>";
});
html += '<div class="cpg-dist-center' + (rows.length ? " has-items" : "") + '" data-drop-for="' + esc(cid) + '">' +
@@ -608,6 +628,8 @@
if (want > max) { want = max; e.target.value = max; }
entry.count = want;
li.querySelector(".cpg-dist-unit").textContent = "박스 · " + (want * (units[entry.key] || 0)) + "개";
var tree = li.querySelector(".cpg-dist-tree");
if (tree) tree.outerHTML = treeHtml(entry);
renderSummary();
updateCenterTotals(cid);
});
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829h" />{% endblock %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829i" />{% endblock %}
{% block content %}
<section class="cpg">
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829h" />{% endblock %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829i" />{% endblock %}
{% block content %}
<section class="cpg">
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829h" />{% endblock %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829i" />{% endblock %}
{% block content %}
<section class="cpg">
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829h" />{% endblock %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829i" />{% endblock %}
{% block content %}
<section class="cpg">
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829h" />{% endblock %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829i" />{% endblock %}
{% block content %}
<section class="cpg">
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829h" />{% endblock %}
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260829i" />{% endblock %}
{% block content %}
<section class="cpg">