|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
|
{% extends "erp_base.html" %}
|
|
|
|
|
|
|
|
|
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260901j" />{% endblock %}
|
|
|
|
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260901k" />{% endblock %}
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
|
|
|
|
<section class="cpg">
|
|
|
|
@@ -264,6 +264,27 @@
|
|
|
|
|
function prodKey(code) { return "p:" + code; }
|
|
|
|
|
function mixKey(boxName, idx) { return "m:" + boxName + "#" + idx; }
|
|
|
|
|
|
|
|
|
|
// 자투리 혼합 박스에 쓸 상자 종류 — 요약 카드에서 고른다(표시용).
|
|
|
|
|
var MIX_TYPES = ["쿠팡상자", "3호상자", "6호상자"];
|
|
|
|
|
var mixType = {}; // mixKey -> 고른 상자 종류
|
|
|
|
|
var mixOwner = {}; // mixKey -> 센터명(업로드로 만들어진 경우)
|
|
|
|
|
|
|
|
|
|
function mixTypeOf(key) { return mixType[key] || MIX_TYPES[0]; }
|
|
|
|
|
|
|
|
|
|
function mixLabel(key, idx) {
|
|
|
|
|
return mixTypeOf(key) + " 혼합 #" + (idx + 1) +
|
|
|
|
|
(mixOwner[key] ? " · " + mixOwner[key] : "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mixTypeSelect(key) {
|
|
|
|
|
var cur = mixTypeOf(key);
|
|
|
|
|
return '<select class="erp-select cpg-box-type" data-type-for="' + esc(key) + '"' +
|
|
|
|
|
' aria-label="상자 종류">' +
|
|
|
|
|
MIX_TYPES.map(function (t) {
|
|
|
|
|
return '<option value="' + esc(t) + '"' + (t === cur ? " selected" : "") + ">" + esc(t) + "</option>";
|
|
|
|
|
}).join("") + "</select>";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function centerName(cid) {
|
|
|
|
|
var hit = centers.filter(function (c) { return String(c.id) === String(cid); })[0];
|
|
|
|
|
return hit ? hit.name : cid;
|
|
|
|
@@ -317,13 +338,15 @@
|
|
|
|
|
units[prodKey(r.product_code)] = r.units_per_box;
|
|
|
|
|
labels[prodKey(r.product_code)] = r.product_name;
|
|
|
|
|
});
|
|
|
|
|
mixOwner = {};
|
|
|
|
|
calc.mixes.forEach(function (m) {
|
|
|
|
|
m.boxes.forEach(function (b, i) {
|
|
|
|
|
var k = mixKey(m.box_name, i);
|
|
|
|
|
var n = 0;
|
|
|
|
|
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) {
|
|
|
|
|
units[k] = n;
|
|
|
|
|
labels[k] = mixLabel(k, i);
|
|
|
|
|
contents[k] = b.items.map(function (it) {
|
|
|
|
|
return { product_code: it.product_code, product_name: it.product_name, quantity: it.quantity };
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
@@ -412,7 +435,8 @@
|
|
|
|
|
calc: { results: calc.results, mixes: calc.mixes },
|
|
|
|
|
units: units, labels: labels, contents: contents,
|
|
|
|
|
openCenters: openCenters.slice(), alloc: alloc, methods: methods,
|
|
|
|
|
stamped: stamped, allStamped: allStamped
|
|
|
|
|
stamped: stamped, allStamped: allStamped,
|
|
|
|
|
mixType: mixType, mixOwner: mixOwner
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -428,6 +452,7 @@
|
|
|
|
|
openCenters = st.openCenters.slice();
|
|
|
|
|
alloc = st.alloc; methods = st.methods;
|
|
|
|
|
stamped = st.stamped; allStamped = st.allStamped;
|
|
|
|
|
mixType = st.mixType || {}; mixOwner = st.mixOwner || {};
|
|
|
|
|
|
|
|
|
|
tbody.innerHTML = "";
|
|
|
|
|
(st.items || []).forEach(function (it) { addRow(it.product_code, it.quantity); });
|
|
|
|
@@ -458,9 +483,9 @@
|
|
|
|
|
items: [], calc: { results: [], mixes: [] },
|
|
|
|
|
units: {}, labels: {}, contents: {},
|
|
|
|
|
openCenters: [], alloc: {}, methods: {},
|
|
|
|
|
stamped: {}, allStamped: false
|
|
|
|
|
stamped: {}, allStamped: false,
|
|
|
|
|
mixType: {}, mixOwner: {}
|
|
|
|
|
};
|
|
|
|
|
var mixOwner = {};
|
|
|
|
|
|
|
|
|
|
function put(cid, key, count) {
|
|
|
|
|
if (count <= 0) return;
|
|
|
|
@@ -498,7 +523,7 @@
|
|
|
|
|
var idx = bucket.boxes.length;
|
|
|
|
|
bucket.boxes.push(b);
|
|
|
|
|
var k = mixKey(mx.box_name, idx);
|
|
|
|
|
mixOwner[k] = g.center_name;
|
|
|
|
|
st.mixOwner[k] = g.center_name;
|
|
|
|
|
put(cid, k, 1);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
@@ -517,8 +542,9 @@
|
|
|
|
|
b.items.forEach(function (it) { n += it.quantity; });
|
|
|
|
|
var k = mixKey(m.box_name, i);
|
|
|
|
|
st.units[k] = n;
|
|
|
|
|
st.labels[k] = m.box_name + " 혼합 #" + (i + 1) +
|
|
|
|
|
(mixOwner[k] ? " · " + mixOwner[k] : "");
|
|
|
|
|
st.mixType[k] = MIX_TYPES[0];
|
|
|
|
|
st.labels[k] = st.mixType[k] + " 혼합 #" + (i + 1) +
|
|
|
|
|
(st.mixOwner[k] ? " · " + st.mixOwner[k] : "");
|
|
|
|
|
st.contents[k] = b.items.map(function (it) {
|
|
|
|
|
return { product_code: it.product_code, product_name: it.product_name, quantity: it.quantity };
|
|
|
|
|
});
|
|
|
|
@@ -691,7 +717,7 @@
|
|
|
|
|
'<path class="cpg-box-flapL" d="M10 20 L2 8 H30 L36 20 Z" />' +
|
|
|
|
|
'<path class="cpg-box-flapR" d="M62 20 L70 8 H42 L36 20 Z" />' +
|
|
|
|
|
'<line class="cpg-box-seam" x1="36" y1="20" x2="36" y2="54" />' +
|
|
|
|
|
'<text class="cpg-box-label" x="36" y="42" text-anchor="middle">쿠팡박스</text>' +
|
|
|
|
|
'<text class="cpg-box-label" x="36" y="42" text-anchor="middle">' + esc(label || "") + "</text>" +
|
|
|
|
|
"</svg>";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -792,10 +818,11 @@
|
|
|
|
|
bh += '<div class="cpg-box-card' + (remain ? " is-draggable" : " is-done") + '"' +
|
|
|
|
|
' data-key="' + esc(key) + '"' +
|
|
|
|
|
' style="animation-delay:' + (n * 60) + 'ms">' +
|
|
|
|
|
'<div class="cpg-box-art">' + boxSvg(b.fill_percent, m.box_name) + "</div>" +
|
|
|
|
|
'<div class="cpg-box-art">' + boxSvg(b.fill_percent, mixTypeOf(key)) + "</div>" +
|
|
|
|
|
'<div class="cpg-box-info">' +
|
|
|
|
|
'<div class="cpg-box-title">' + esc(m.box_name) + " 혼합 #" + (i + 1) +
|
|
|
|
|
'<div class="cpg-box-title">' + esc(mixTypeOf(key)) + " 혼합 #" + (i + 1) +
|
|
|
|
|
(remain ? "" : stampHtml(key)) + "</div>" +
|
|
|
|
|
'<div class="cpg-box-typerow">' + mixTypeSelect(key) + "</div>" +
|
|
|
|
|
'<ul class="cpg-box-items">' + items + "</ul>" +
|
|
|
|
|
'<div class="cpg-box-bar"><span style="width:' + b.fill_percent + '%"></span></div>' +
|
|
|
|
|
'<div class="cpg-box-fillnum">' + b.fill_percent + "% 채움 · " + units[key] + "개</div>" +
|
|
|
|
@@ -1001,6 +1028,7 @@
|
|
|
|
|
|
|
|
|
|
sumBody.addEventListener("mousedown", function (e) {
|
|
|
|
|
if (e.button !== 0) return;
|
|
|
|
|
if (e.target.closest(".cpg-box-type")) return; // 상자 종류 고르는 중
|
|
|
|
|
var card = e.target.closest("[data-key]");
|
|
|
|
|
if (!card || card.classList.contains("is-done")) return;
|
|
|
|
|
drag = { key: card.getAttribute("data-key"), card: card, startX: e.clientX, startY: e.clientY, moved: false, ghost: null };
|
|
|
|
@@ -1032,12 +1060,29 @@
|
|
|
|
|
// 드래그하지 않고 클릭한 경우 — 첫 센터를 기본값으로 대화상자를 연다.
|
|
|
|
|
// (드래그를 끝낸 카드에서 브라우저가 한 번 더 쏘는 click 은 1회만 무시)
|
|
|
|
|
sumBody.addEventListener("click", function (e) {
|
|
|
|
|
if (e.target.closest(".cpg-box-type")) return; // 상자 종류 고르는 중
|
|
|
|
|
var card = e.target.closest("[data-key]");
|
|
|
|
|
if (!card) return;
|
|
|
|
|
if (card === suppressClickOn) { suppressClickOn = null; return; }
|
|
|
|
|
openDialog(card.getAttribute("data-key"), openCenters[0]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 상자 종류 변경 — 라벨(②③)만 바뀌고 배분 수량은 그대로 유지된다.
|
|
|
|
|
sumBody.addEventListener("change", function (e) {
|
|
|
|
|
var sel = e.target.closest(".cpg-box-type");
|
|
|
|
|
if (!sel) return;
|
|
|
|
|
var key = sel.getAttribute("data-type-for");
|
|
|
|
|
mixType[key] = sel.value;
|
|
|
|
|
calc.mixes.forEach(function (m) {
|
|
|
|
|
m.boxes.forEach(function (b, i) {
|
|
|
|
|
var k = mixKey(m.box_name, i);
|
|
|
|
|
if (k === key) labels[k] = mixLabel(k, i);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
render();
|
|
|
|
|
msg.textContent = "상자 종류를 " + sel.value + " 로 바꿨습니다.";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (distList) {
|
|
|
|
|
distList.addEventListener("input", function (e) {
|
|
|
|
|
if (!e.target.classList.contains("cpg-dist-qty")) return;
|
|
|
|
@@ -1367,7 +1412,8 @@
|
|
|
|
|
alloc: alloc,
|
|
|
|
|
methods: methods,
|
|
|
|
|
stamped: stamped,
|
|
|
|
|
allStamped: allStamped
|
|
|
|
|
allStamped: allStamped,
|
|
|
|
|
mixType: mixType
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1391,6 +1437,17 @@
|
|
|
|
|
methods = snap.methods && typeof snap.methods === "object" ? snap.methods : {};
|
|
|
|
|
stamped = snap.stamped && typeof snap.stamped === "object" ? snap.stamped : {};
|
|
|
|
|
allStamped = !!snap.allStamped;
|
|
|
|
|
if (snap.mixType && typeof snap.mixType === "object") {
|
|
|
|
|
Object.keys(snap.mixType).forEach(function (k) {
|
|
|
|
|
if (k in units) mixType[k] = snap.mixType[k];
|
|
|
|
|
});
|
|
|
|
|
calc.mixes.forEach(function (m) {
|
|
|
|
|
m.boxes.forEach(function (b, i) {
|
|
|
|
|
var k = mixKey(m.box_name, i);
|
|
|
|
|
labels[k] = mixLabel(k, i);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return skipped;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|