08ebe7b53d
요청은 스킨 detail.html 의 `const numbers = [...]` 를 고치는 것이었지만, 카페24
Admin API 로는 스킨 HTML 파일을 읽거나 쓸 수 없다. 확인 결과 테마는 조회만
가능하고(GET /admin/themes) 스킨 파일 엔드포인트가 없다. 쓸 수 있는 것은 테마
페이지와 스크립트 태그뿐이다.
그래서 같은 결과를 상품 상세설명 안의 CSS 로 낸다. 상세설명은 이미 우리가 쓸 수
있는 영역이고, 상품별로 켜고 끌 수 있으며, 상태가 그 상품 소스에 그대로 보인다.
새 권한이나 재인증도 필요하지 않다.
<style id="cf24-hide-common-promo">.edb-img-tag-w{display:none !important}</style>
id 로 우리 블록만 찾으므로 사람이 쓴 <style> 은 건드리지 않는다. 넣기/빼기는
멱등이고 소스 정리(format_html)를 거쳐도 상태가 유지된다.
PC·모바일 모두 반영한다. 미분리 상품은 같은 HTML 이 양쪽에 들어가고, 분리 상품은
모바일 본문을 건드리지 않되 이 블록만 모바일에도 맞춘다 — 양쪽에 걸지 않으면 한쪽에
홍보가 그대로 남는다. PC/모바일 상태가 다르면 화면에 불일치를 알린다.
"변경 없음" 판정에 모바일 변경도 포함시켰다. PC 는 그대로인데 모바일 숨김만
바뀌는 경우가 있어서, 예전 조건이면 아무 일도 하지 않고 끝났다.
스킨의 numbers 목록과는 독립이며 충돌하지 않는다(스킨은 요소 제거, 이쪽은 CSS 숨김).
이미 목록에 있는 상품은 그대로 두면 된다.
검증: 유닛테스트 49개 통과(신규 4개 — 추가/제거 왕복, 멱등, 포맷 통과 후 인식,
사람이 쓴 style 보존).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
129 lines
6.3 KiB
HTML
129 lines
6.3 KiB
HTML
{# 오른쪽 편집기 조각.
|
|
전체 페이지(products.html)가 include 하고, JS 가 /products/{no}/pane 으로
|
|
같은 조각만 다시 받아 끼워 넣는다. 그래서 여기에는 <script> 를 두지 않는다
|
|
(innerHTML 로 삽입된 script 는 실행되지 않는다 — JS 는 products.html 에 있고
|
|
삽입 후 cf24BindEditor() 로 다시 연결한다). #}
|
|
|
|
{% if editor_error %}
|
|
<div class="cf24-flash cf24-flash-err">
|
|
카페24 조회에 실패했습니다: {{ editor_error }}<br />
|
|
<a href="/cafe24/system">시스템 화면에서 연결 상태를 확인하세요.</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="cf24-editor-head">
|
|
<div>
|
|
<h3 class="cf24-editor-title">{{ info.product_name or '상품' }}</h3>
|
|
<p class="cf24-editor-sub">
|
|
상품번호 {{ product_no }}
|
|
{% if info.product_code %}· <code>{{ info.product_code }}</code>{% endif %}
|
|
{% if info.price %}· {{ info.price }}{% endif %}
|
|
{% if info.updated_date %}· 최근 수정 {{ info.updated_date }}{% endif %}
|
|
</p>
|
|
</div>
|
|
<div class="cf24-editor-badges">
|
|
{% if info.display %}<span class="erp-badge cf24-badge-ok">진열</span>
|
|
{% else %}<span class="erp-badge cf24-badge-off">미진열</span>{% endif %}
|
|
{% if info.selling %}<span class="erp-badge cf24-badge-ok">판매</span>
|
|
{% else %}<span class="erp-badge cf24-badge-off">중지</span>{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if desc %}
|
|
<p class="cf24-note">
|
|
{% if desc.separated_mobile %}
|
|
<strong>PC/모바일 분리 사용 상품입니다.</strong> 아래 적용은 PC 만 바꿉니다 —
|
|
모바일({{ desc.mobile_description | length }}자)은 카페24 관리자에서 따로 반영해야 합니다.
|
|
{% else %}
|
|
모바일은 PC와 동일 설정이라 적용 시 <strong>함께 반영</strong>됩니다.
|
|
{% endif %}
|
|
{% if desc.mobile_differs %}<span class="cf24-warn">현재 PC/모바일 내용이 다릅니다.</span>{% endif %}
|
|
<br />
|
|
소스는 <strong>태그마다 줄을 나눠 정리</strong>해서 보여주며, <strong>적용하면 정리된 소스가
|
|
그대로 카페24에 저장</strong>됩니다. 줄바꿈·들여쓰기만 바뀌고 태그 구조는 그대로이며,
|
|
이미지가 벌어지지 않도록 <code>img</code>·<code>span</code> 같은 인라인 요소와
|
|
<code><style></code> 안쪽은 건드리지 않습니다.
|
|
<br />
|
|
이미지 경로의 한글 파일명은 카페24에 <code>%EC%9A%A9…</code> 로 저장되어 있습니다.
|
|
여기서는 한글로 보여주고, 적용할 때 원래 형식으로 되돌립니다.
|
|
</p>
|
|
|
|
<form class="cf24-editor-form" method="post"
|
|
action="/cafe24/products/{{ product_no }}/apply"
|
|
data-confirm="카페24 쇼핑몰에 바로 반영됩니다. 적용할까요? 직전 내용은 자동으로 백업되어 되돌릴 수 있습니다.">
|
|
<input type="hidden" name="base_fingerprint" value="{{ fingerprint }}" />
|
|
<input type="hidden" name="list_query" value="{{ list_query }}" />
|
|
|
|
<div class="cf24-editor-bar">
|
|
<span class="cf24-muted">
|
|
PC 상세설명 HTML · {{ desc.description | length }}자
|
|
<label class="cf24-check-inline" title="상세페이지 상단의 공통 홍보 영역(.edb-img-tag-w)을 이 상품에서만 숨깁니다. PC·모바일 모두 적용됩니다.">
|
|
<input type="checkbox" name="hide_promo" value="1"
|
|
{% if promo_hidden %}checked{% endif %} />
|
|
상단 공통 홍보 숨기기
|
|
{% if promo_hidden != promo_hidden_mobile %}
|
|
<span class="cf24-warn">(PC/모바일 상태 불일치 — 적용하면 맞춰집니다)</span>
|
|
{% endif %}
|
|
</label>
|
|
</span>
|
|
<span class="cf24-editor-bar-right">
|
|
<input class="cf24-memo" type="text" name="memo" maxlength="200"
|
|
placeholder="변경 메모 (버전 이력에 남습니다)" />
|
|
<button class="erp-btn erp-btn-outline" type="button" data-copy="cf24-html-pc">복사</button>
|
|
<button class="erp-btn erp-btn-primary" type="submit">카페24에 적용</button>
|
|
</span>
|
|
</div>
|
|
|
|
{# 색칠된 <pre> 위에 투명한 <textarea> 를 겹쳐 문법 강조를 만든다.
|
|
<pre> 가 크기를 정하고 <textarea> 는 inset:0 으로 그 위를 정확히 덮는다.
|
|
줄바꿈을 하지 않고(wrap=off) 가로로 스크롤하므로 줄 번호가 항상 맞는다.
|
|
두 요소의 폰트·여백이 다르면 글자가 어긋난다 — CSS 에서 함께 관리한다. #}
|
|
<div class="cf24-code" id="cf24-code-pc">
|
|
<div class="cf24-gutter" aria-hidden="true"><div class="cf24-gutter-inner" id="cf24-gutter-pc"></div></div>
|
|
<div class="cf24-code-body">
|
|
<pre class="cf24-code-hl" id="cf24-hl-pc" aria-hidden="true"></pre>
|
|
<textarea id="cf24-html-pc" class="cf24-code-input" name="html" wrap="off"
|
|
spellcheck="false" autocapitalize="off" autocorrect="off">{{ html_pc }}</textarea>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
{% if desc.separated_mobile or desc.mobile_differs %}
|
|
<details class="cf24-details">
|
|
<summary>모바일 상세설명 HTML 보기 (읽기 전용 · {{ desc.mobile_description | length }}자)</summary>
|
|
<textarea id="cf24-html-mo" class="cf24-html" rows="12" readonly
|
|
spellcheck="false">{{ html_mobile }}</textarea>
|
|
<div class="cf24-actions">
|
|
<button type="button" class="erp-btn erp-btn-outline" data-copy="cf24-html-mo">복사</button>
|
|
</div>
|
|
</details>
|
|
{% endif %}
|
|
|
|
<details class="cf24-details">
|
|
<summary>버전 이력 {% if revisions %}({{ revisions | length }}건){% endif %}</summary>
|
|
{% if revisions %}
|
|
<div class="cf24-scroll">
|
|
<table class="erp-table cf24-compact">
|
|
<thead>
|
|
<tr><th>시각</th><th>유형</th><th>길이</th><th>작업자</th><th>메모</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for rev in revisions %}
|
|
<tr>
|
|
<td class="cf24-nowrap">{{ rev.created_at }}</td>
|
|
<td class="cf24-nowrap"><code>{{ rev.revision_type }}</code></td>
|
|
<td class="cf24-nowrap">{{ rev.html_length }}자</td>
|
|
<td class="cf24-nowrap">{{ rev.created_by or '—' }}</td>
|
|
<td>{{ rev.memo or '' }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<p class="cf24-muted">버전 선택 복원은 Phase 6 에서 붙습니다. 내용은 모두 보관됩니다.</p>
|
|
{% else %}
|
|
<p class="cf24-muted">아직 이 상품의 변경 이력이 없습니다.</p>
|
|
{% endif %}
|
|
</details>
|
|
{% endif %}
|