// main.js (FULL REPLACE) // 목적: 프론트에서 /api/* 호출 테스트 + 결과 화면 출력 // - 같은 도메인(예: https://api.myarchi3.xyz)에서 서빙되면 CORS 없이 상대경로로 동작함. const API_BASE = ""; // ""이면 same-origin. 필요하면 "https://api.myarchi3.xyz" 처럼 고정 가능. function $(sel) { return document.querySelector(sel); } function apiUrl(path) { // path는 "/api/..." 형태로 넣기 if (!API_BASE) return path; return API_BASE.replace(/\/$/, "") + path; } async function fetchJson(url, opts = {}) { const res = await fetch(url, { ...opts, headers: { "Content-Type": "application/json", ...(opts.headers || {}), }, }); const ct = res.headers.get("content-type") || ""; const isJson = ct.includes("application/json"); let body; if (isJson) body = await res.json(); else body = await res.text(); if (!res.ok) { const msg = typeof body === "string" ? body : JSON.stringify(body, null, 2) || `${res.status} ${res.statusText}`; throw new Error(`HTTP ${res.status} ${res.statusText}\n\n${msg}`); } return body; } function renderApp() { // 기존 Hello world UI는 유지해도 되지만, 여기서는 앱 UI로 교체 document.body.innerHTML = `

my-archi-3 테스트 콘솔

현재 페이지 오리진: ${location.origin} / API_BASE: ${API_BASE || "(same-origin)"}

대기중

응답


    
`; // 버튼 기본 스타일(간단) document.querySelectorAll("button").forEach((b) => { b.style.padding = "10px 12px"; b.style.borderRadius = "10px"; b.style.border = "1px solid rgba(0,0,0,.2)"; b.style.cursor = "pointer"; b.style.background = "white"; }); } function getPayload() { return { use_main: $("#use_main").value.trim(), gross_floor_area_m2: Number($("#gfa").value || 0), floors_above: Number($("#floors").value || 0), parking_planned: $("#parking").checked, notes: $("#notes").value.trim(), }; } function setStatus(msg) { $("#status").textContent = msg; } function print(obj) { const out = $("#out"); if (typeof obj === "string") out.textContent = obj; else out.textContent = JSON.stringify(obj, null, 2); } async function handle(action) { try { setStatus("요청 중..."); print(""); if (action === "catalog") { const data = await fetchJson(apiUrl("/api/catalog"), { method: "GET" }); print(data); setStatus("완료: catalog"); return; } const payload = getPayload(); if (action === "recommend") { const data = await fetchJson(apiUrl("/api/recommend"), { method: "POST", body: JSON.stringify(payload), }); print(data); setStatus("완료: recommend"); return; } if (action === "seed") { const data = await fetchJson(apiUrl("/api/report/seed"), { method: "POST", body: JSON.stringify(payload), }); print(data); setStatus("완료: report/seed"); return; } if (action === "html") { // HTML은 JSON이 아닐 가능성이 있어 text로 받는 방식도 대비 const res = await fetch(apiUrl("/api/report/html"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const text = await res.text(); if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}\n\n${text}`); // 새 탭으로 HTML 보기 const blob = new Blob([text], { type: "text/html; charset=utf-8" }); const url = URL.createObjectURL(blob); window.open(url, "_blank", "noopener,noreferrer"); print(text.slice(0, 2000) + (text.length > 2000 ? "\n\n...(생략)" : "")); setStatus("완료: report/html (새 탭 열림)"); return; } } catch (e) { setStatus("에러"); print(String(e?.stack || e?.message || e)); } } document.addEventListener("DOMContentLoaded", () => { renderApp(); $("#btnCatalog").addEventListener("click", () => handle("catalog")); $("#btnRecommend").addEventListener("click", () => handle("recommend")); $("#btnSeed").addEventListener("click", () => handle("seed")); $("#btnHtml").addEventListener("click", () => handle("html")); });