상품·주문·수동 결제 승인·권리·청구·축소·해지·AI Wallet 표시·사용량 배정 화면·경고 엔진 (§6·§13·§27)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
zzabisagent-lab
2026-10-26 11:26:35 +00:00
co-authored by Claude Fable 5.1
parent c90ac27596
commit c397452acd
21 changed files with 1147 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
/* portal/commerce/public/products.js — 상품 목록(§6.1). 가격·한도는 서버(product_versions)에서 온다. 미확정 정책은 숫자 대신 '미확정 정책' 으로 보인다. */
(() => {
const el = document.getElementById('products'); const esc = aw.esc; const GB = 1024 ** 3;
const money = (n) => Number(n).toLocaleString('ko-KR') + '원'; const gb = (b) => (b / GB).toFixed(0) + ' GB';
async function load() {
try {
const d = await aw.api('GET', '/api/commerce/products');
if (!d.products.length) { aw.state(el, 'empty', '판매 중인 상품이 없습니다. 운영자에게 문의하세요'); return; }
el.innerHTML = `<p class="alert info">ⓘ 결제 방식: ${esc(d.paymentMethods.map((m) => m.label).join(', '))} — 자동 결제는 지원하지 않습니다.</p>` + `<div class="cards">${d.products.map((p) => `<div class="card"><h2>${esc(p.name)} <span class="sub">v${p.version}</span></h2><p class="sub">${esc(p.audience)}</p><p>${esc(p.description || '')}</p><p class="stat">${money(p.price)}<span class="sub">/${p.billingCycle === 'monthly' ? '월' : '년'} + 세금 ${money(p.tax)} = ${money(p.total)}</span></p>
<dl class="kv"><dt>사이트 수</dt><dd>${p.limits.sites}개</dd><dt>웹 디스크</dt><dd>${gb(p.limits.web_disk)}</dd><dt>월간 웹 아웃바운드</dt><dd>${gb(p.limits.web_out)}</dd><dt>메일 저장 공간</dt><dd>${gb(p.limits.mail_storage)}</dd><dt>월간 메일 통수</dt><dd>${p.limits.mail_msgs.toLocaleString('ko-KR')}통(송신+수신)</dd><dt>메일함</dt><dd>${p.limits.mailboxes}개</dd></dl>
<h3>추가 옵션</h3><ul>${p.options.map((o) => `<li>${esc(o.name)} — ${money(o.price)}${o.per === 'site' ? ' (사이트당)' : ''}</li>`).join('')}</ul>
<h3>제공 범위</h3><ul>${p.includes.map((x) => `<li>${esc(x)}</li>`).join('')}</ul><h3>제외</h3><ul>${p.excludes.map((x) => `<li>${esc(x)}</li>`).join('')}</ul>
${p.deferred.length ? `<h3>미확정 정책</h3><ul>${p.deferred.map((x) => `<li><span class="badge warning">! 미확정 정책</span> ${esc(x.key)} — ${esc(x.note)}</li>`).join('')}</ul>` : ''}
<p class="sub">사용량 경고 ${p.warnLevels.join('·')}% · 승인 방식: 운영자 수동 승인 · 적용 ${esc(p.effectiveFrom.slice(0, 10))}</p>
<div class="actions"><a class="btn primary" href="/order/new?product=${esc(p.id)}">주문</a></div></div>`).join('')}</div>` +
`<div class="card"><h2>도메인 등록</h2>${d.domainRegistration.enabled ? `<p>등록기관(${esc(d.domainRegistration.registrar || '')})을 통해 도메인을 검색·등록할 수 있습니다.</p>` : `<p class="muted">${esc(d.domainRegistration.note)}</p>`}</div>`;
} catch (e) { aw.state(el, 'failed', e.message, { retry: load }); }
}
load();
})();