feat(cupang): 등록 제품명 표 정렬 + 박스 입수량 시드 SQL
제품명/제품코드 헤더 클릭으로 오름·내림차순 토글. Intl.Collator(ko, numeric) 사용해 "미라네 2호"가 "미라네 10호"보다 앞에 오도록 정렬. 검색 비활성 상태에서도 동작하게 스크립트를 search_enabled 밖에 배치. 박스 입수량 14건(미라네 1~7호, 황토 김치통 1~7호) 시드 SQL 추가. 피킹비 전용 컬럼이 없어 memo 에 기록. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260530p" />{% endblock %}
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260828s" />{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="cpg">
|
<section class="cpg">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260530p" />{% endblock %}
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260828s" />{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="cpg">
|
<section class="cpg">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260530p" />{% endblock %}
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260828s" />{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="cpg">
|
<section class="cpg">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260530p" />{% endblock %}
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260828s" />{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="cpg">
|
<section class="cpg">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260530p" />{% endblock %}
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260828s" />{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="cpg">
|
<section class="cpg">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260530p" />{% endblock %}
|
{% block head_extra %}<link rel="stylesheet" href="/static/cupang.css?v=20260828s" />{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="cpg">
|
<section class="cpg">
|
||||||
@@ -38,10 +38,17 @@
|
|||||||
<span class="erp-muted">폼의 제품명 드롭다운에 노출</span></div>
|
<span class="erp-muted">폼의 제품명 드롭다운에 노출</span></div>
|
||||||
<div class="erp-table-wrap cpg-reg-scroll">
|
<div class="erp-table-wrap cpg-reg-scroll">
|
||||||
<table class="erp-table">
|
<table class="erp-table">
|
||||||
<thead><tr><th>제품명</th><th>제품코드</th><th>상태</th><th>동작</th></tr></thead>
|
<thead>
|
||||||
<tbody>
|
<tr>
|
||||||
|
<th><button type="button" class="cpg-sort" data-sort-key="name">제품명<span class="cpg-sort-ind" aria-hidden="true"></span></button></th>
|
||||||
|
<th><button type="button" class="cpg-sort" data-sort-key="code">제품코드<span class="cpg-sort-ind" aria-hidden="true"></span></button></th>
|
||||||
|
<th>상태</th>
|
||||||
|
<th>동작</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="cpg-prod-tbody">
|
||||||
{% for p in products %}
|
{% for p in products %}
|
||||||
<tr {% if not p.active %}style="opacity:.55"{% endif %}>
|
<tr data-name="{{ p.product_name }}" data-code="{{ p.product_code }}" {% if not p.active %}style="opacity:.55"{% endif %}>
|
||||||
<td>{{ p.product_name }}</td>
|
<td>{{ p.product_name }}</td>
|
||||||
<td>{{ p.product_code }}</td>
|
<td>{{ p.product_code }}</td>
|
||||||
<td>{% if p.active %}<span class="erp-badge erp-badge-success">활성</span>{% else %}<span class="erp-badge erp-badge-neutral">비활성</span>{% endif %}</td>
|
<td>{% if p.active %}<span class="erp-badge erp-badge-success">활성</span>{% else %}<span class="erp-badge erp-badge-neutral">비활성</span>{% endif %}</td>
|
||||||
@@ -67,7 +74,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if not products %}
|
{% if not products %}
|
||||||
<tr><td colspan="4" class="erp-muted">등록된 제품명이 없습니다. 왼쪽에서 선택해 등록하세요.</td></tr>
|
<tr class="cpg-no-sort"><td colspan="4" class="erp-muted">등록된 제품명이 없습니다. 왼쪽에서 선택해 등록하세요.</td></tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -77,6 +84,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 등록된 제품명 표 — 제품명/제품코드 오름차순·내림차순 정렬 (클라이언트).
|
||||||
|
(function () {
|
||||||
|
var tbody = document.getElementById("cpg-prod-tbody");
|
||||||
|
if (!tbody) return;
|
||||||
|
var buttons = Array.prototype.slice.call(document.querySelectorAll(".cpg-sort"));
|
||||||
|
var state = { key: null, dir: 1 };
|
||||||
|
var collator = new Intl.Collator("ko", { numeric: true, sensitivity: "base" });
|
||||||
|
|
||||||
|
function apply() {
|
||||||
|
var rows = Array.prototype.slice.call(tbody.querySelectorAll("tr:not(.cpg-no-sort)"));
|
||||||
|
if (rows.length < 2) return;
|
||||||
|
rows.sort(function (a, b) {
|
||||||
|
var av = a.getAttribute("data-" + state.key) || "";
|
||||||
|
var bv = b.getAttribute("data-" + state.key) || "";
|
||||||
|
return collator.compare(av, bv) * state.dir;
|
||||||
|
});
|
||||||
|
rows.forEach(function (r) { tbody.appendChild(r); });
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.forEach(function (btn) {
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
var key = btn.getAttribute("data-sort-key");
|
||||||
|
if (state.key === key) { state.dir = -state.dir; }
|
||||||
|
else { state.key = key; state.dir = 1; }
|
||||||
|
buttons.forEach(function (b) {
|
||||||
|
var on = b === btn;
|
||||||
|
b.classList.toggle("is-asc", on && state.dir === 1);
|
||||||
|
b.classList.toggle("is-desc", on && state.dir === -1);
|
||||||
|
b.closest("th").setAttribute("aria-sort", on ? (state.dir === 1 ? "ascending" : "descending") : "none");
|
||||||
|
});
|
||||||
|
apply();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
{% if search_enabled %}
|
{% if search_enabled %}
|
||||||
<script type="application/json" id="cpg-registered">{{ registered_codes | tojson }}</script>
|
<script type="application/json" id="cpg-registered">{{ registered_codes | tojson }}</script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -305,3 +305,24 @@
|
|||||||
.cpg-upb-unit { font-size: 13px; color: var(--color-midtone-gray); }
|
.cpg-upb-unit { font-size: 13px; color: var(--color-midtone-gray); }
|
||||||
/* 메모: 프레임 전체 너비 */
|
/* 메모: 프레임 전체 너비 */
|
||||||
.cpg .cpg-brule-fields .cpg-brule-memo { width: 100%; min-width: 0; max-width: 100%; box-sizing: border-box; }
|
.cpg .cpg-brule-fields .cpg-brule-memo { width: 100%; min-width: 0; max-width: 100%; box-sizing: border-box; }
|
||||||
|
|
||||||
|
/* 등록된 제품명 표 — 정렬 가능한 헤더 */
|
||||||
|
.cpg-sort {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: none;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cpg-sort:hover { text-decoration: underline; }
|
||||||
|
.cpg-sort-ind::after {
|
||||||
|
content: "↕";
|
||||||
|
opacity: .35;
|
||||||
|
font-size: .85em;
|
||||||
|
}
|
||||||
|
.cpg-sort.is-asc .cpg-sort-ind::after { content: "▲"; opacity: 1; }
|
||||||
|
.cpg-sort.is-desc .cpg-sort-ind::after { content: "▼"; opacity: 1; }
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
-- ════════════════════════════════════════════════════════════
|
||||||
|
-- 쿠팡 밀크런 — 박스 입수량 규칙 초기 입력 (cupang_db)
|
||||||
|
--
|
||||||
|
-- 실행:
|
||||||
|
-- docker exec -i postgres-db psql -U postgres -d cupang_db \
|
||||||
|
-- < /opt/www/main/scripts/sql/cupang_box_rules_seed.sql
|
||||||
|
--
|
||||||
|
-- 제품코드는 cupang_products 카탈로그 기준(2026-08-28 확인).
|
||||||
|
-- 같은 product_code 는 덮어쓴다(ON CONFLICT DO UPDATE).
|
||||||
|
-- 피킹비는 전용 컬럼이 없어 memo 에 기록한다.
|
||||||
|
-- ════════════════════════════════════════════════════════════
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
INSERT INTO cupang_box_rules
|
||||||
|
(product_code, product_name_snapshot, box_name, units_per_box, memo, active)
|
||||||
|
VALUES
|
||||||
|
('MS-1001', '미라네 1호 세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||||
|
('MS-1002', '미라네 2호 세트', '쿠팡 2호', 8, '피킹비 1100원', TRUE),
|
||||||
|
('MS-1003', '미라네 3호 세트', '쿠팡 2호', 8, '피킹비 1200원', TRUE),
|
||||||
|
('MS-1004', '미라네 4호 세트', '쿠팡 2호', 8, '피킹비 1000원', TRUE),
|
||||||
|
('MS-1005', '미라네 5호 세트', '쿠팡 2호', 8, '피킹비 650원', TRUE),
|
||||||
|
('MS-1006', '미라네 6호 세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||||
|
('MS-1007', '미라네 7호 세트', '쿠팡 2호', 8, '피킹비 850원', TRUE),
|
||||||
|
('MS-9812', '황토 김치통 1호세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||||
|
('MS-9813', '황토 김치통 2호세트', '쿠팡 2호', 8, '피킹비 650원', TRUE),
|
||||||
|
('MS-9814', '황토 김치통 3호세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||||
|
('MS-9815', '황토 김치통 4호세트', '쿠팡 3호', 2, '피킹비 850원', TRUE),
|
||||||
|
('MS-9816', '황토 김치통 5호세트', '쿠팡 3호', 2, '피킹비 900원', TRUE),
|
||||||
|
('MS-9817', '황토 김치통 6호세트', '쿠팡 6호', 1, '피킹비 1000원', TRUE),
|
||||||
|
('MS-9818', '황토 김치통 7호세트', '쿠팡 6호', 1, '피킹비 1100원', TRUE)
|
||||||
|
ON CONFLICT (product_code) DO UPDATE
|
||||||
|
SET product_name_snapshot = EXCLUDED.product_name_snapshot,
|
||||||
|
box_name = EXCLUDED.box_name,
|
||||||
|
units_per_box = EXCLUDED.units_per_box,
|
||||||
|
memo = EXCLUDED.memo,
|
||||||
|
active = TRUE;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- 결과 확인
|
||||||
|
SELECT product_code, product_name_snapshot, box_name, units_per_box, memo
|
||||||
|
FROM cupang_box_rules
|
||||||
|
ORDER BY product_code;
|
||||||
Reference in New Issue
Block a user