fix(cafe24): 통합 목록 행 순서를 품목(진열) 순서로, 깨진 썸네일은 "없음"
- options 응답의 옵션값 순서는 등록 순서라 쇼핑몰 순서와 달랐다. 품목 목록 순서(카페24가 진열순서대로 돌려줌)를 기준으로 행을 만들고, 품목이 안 잡힌 옵션값은 뒤에 붙인다. 옵션 PUT 짝맞춤용 index 는 그대로 유지하고, 드래그 변경 판정은 처음 그린 위치(data-pos) 기준으로. - 카페24가 경로만 주고 파일이 없는 썸네일은 onerror 로 "없음" 표시. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -128,10 +128,13 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
// 카페24가 경로는 주지만 파일이 없는 경우가 있다(깨진 그림) — 실패하면 "없음"으로 바꾼다.
|
||||
var THUMB_EMPTY = '<div class="cf24-opt-thumb-empty">없음</div>';
|
||||
function thumbHtml(src, title) {
|
||||
return src
|
||||
? '<img class="cf24-opt-thumb" src="' + esc(src) + '" alt="" title="' + esc(title || "") + '" />'
|
||||
: '<div class="cf24-opt-thumb-empty">없음</div>';
|
||||
? '<img class="cf24-opt-thumb" src="' + esc(src) + '" alt="" title="' + esc(title || "") +
|
||||
'" onerror="this.outerHTML=\'' + THUMB_EMPTY.replace(/"/g, """) + '\'" />'
|
||||
: THUMB_EMPTY;
|
||||
}
|
||||
|
||||
// 썸네일 파일 선택 → 업로드 → hidden 두 개(option_image_file, option_link_image)에 경로
|
||||
@@ -176,27 +179,38 @@
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
통합 목록 — 옵션값 1 : 품목 1
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
// 행 순서는 **품목 목록 순서**(카페24가 진열순서대로 돌려준다 — 쇼핑몰에 보이는 순서)를
|
||||
// 따른다. options 응답의 옵션값 순서는 등록 순서라 실제와 다를 수 있다(실물 확인).
|
||||
// index 는 options 응답 안 위치 — 옵션 PUT 은 이 위치로 짝을 맞춰야 하므로 유지한다.
|
||||
function unifiedRows() {
|
||||
var opt = state.option;
|
||||
if (!opt || !opt.has_option) return [];
|
||||
var group = opt.options[0];
|
||||
return group.option_value.map(function (v, vi) {
|
||||
var variant = null;
|
||||
for (var i = 0; i < state.variants.length; i++) {
|
||||
var cand = state.variants[i];
|
||||
if (cand.options.length && cand.options[0].value === v.option_text) { variant = cand; break; }
|
||||
}
|
||||
return { index: vi, value: v, variant: variant };
|
||||
var byText = {};
|
||||
group.option_value.forEach(function (v, vi) { byText[v.option_text] = { index: vi, value: v, variant: null }; });
|
||||
var rows = [];
|
||||
state.variants.forEach(function (variant) {
|
||||
if (!variant.options.length) return;
|
||||
var r = byText[variant.options[0].value];
|
||||
if (!r || r.variant) return; // 옵션값이 없거나 이미 배정됨
|
||||
r.variant = variant;
|
||||
rows.push(r);
|
||||
});
|
||||
group.option_value.forEach(function (v) {
|
||||
var r = byText[v.option_text];
|
||||
if (rows.indexOf(r) < 0) rows.push(r); // 품목이 안 잡힌 옵션값은 뒤에
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
|
||||
function rowHtml(r, isNew, canDrag) {
|
||||
function rowHtml(r, isNew, canDrag, position) {
|
||||
var v = r.value || { option_text: "", option_image_file: "", option_link_image: "", option_color: "" };
|
||||
var variant = r.variant;
|
||||
var thumbSrc = v.option_image_file || v.option_link_image ||
|
||||
(state.option && state.option.has_option ? variantImageFor(state.option.options[0].option_name, v.option_text) : "");
|
||||
var code = variant ? variant.variant_code : "";
|
||||
return '<tr class="cf24-u-row" data-index="' + (r.index == null ? "" : r.index) + '" data-code="' + esc(code) + '">' +
|
||||
// data-index: options 응답 안 위치(옵션 PUT 짝맞춤용) / data-pos: 처음 그린 순서(순서 변경 판정용)
|
||||
return '<tr class="cf24-u-row" data-index="' + (r.index == null ? "" : r.index) + '" data-pos="' + (position == null ? "" : position) + '" data-code="' + esc(code) + '">' +
|
||||
'<td class="cf24-u-drag">' + (canDrag ? '<span class="cf24-drag-handle" draggable="true" title="드래그하여 순서 변경">⋮⋮</span>' : "") + "</td>" +
|
||||
'<td class="cf24-u-thumb"><span class="cf24-opt-thumb-slot">' + thumbHtml(thumbSrc, v.option_image_file ? "옵션 버튼 이미지" : v.option_link_image ? "옵션 연결 이미지" : "품목 이미지") + "</span>" +
|
||||
'<input type="hidden" name="option_image_file" value="' + esc(v.option_image_file || "") + '" />' +
|
||||
@@ -234,7 +248,7 @@
|
||||
'<th class="cf24-u-drag"></th><th class="cf24-u-thumb">썸네일</th><th>옵션값 이름</th><th class="cf24-v-syscode">품목코드</th>' +
|
||||
'<th class="cf24-v-code">자체 품목코드</th><th class="cf24-v-amount">추가금액</th><th class="cf24-v-flag">진열</th><th class="cf24-v-flag">판매</th><th class="cf24-u-del"></th>' +
|
||||
"</tr></thead><tbody id=\"cf24-u-body\">";
|
||||
rows.forEach(function (r) { html += rowHtml(r, false, canDrag); });
|
||||
rows.forEach(function (r, i) { html += rowHtml(r, false, canDrag, i); });
|
||||
if (isNew) html += rowHtml({ index: null, value: null, variant: null }, true, true);
|
||||
html += "</tbody></table></div>" +
|
||||
'<p class="cf24-side-note cf24-u-note">' +
|
||||
@@ -319,7 +333,7 @@
|
||||
function markOrder(tbody) {
|
||||
var changed = false;
|
||||
Array.prototype.forEach.call(tbody.children, function (tr, i) {
|
||||
var orig = tr.dataset.index === "" ? null : parseInt(tr.dataset.index, 10);
|
||||
var orig = tr.dataset.pos === "" || tr.dataset.pos == null ? null : parseInt(tr.dataset.pos, 10);
|
||||
if (orig !== null && orig !== i) changed = true;
|
||||
});
|
||||
tbody.classList.toggle("is-order-dirty", changed);
|
||||
|
||||
Reference in New Issue
Block a user