Files
crawlmanager/views/admin/adsense.ejs
T
chpark dcae228a24 fix: 전 페이지 서버사이드 렌더링으로 전환 (초기 데이터 fetch 제거)
- 모든 관리자 페이지에서 DB 데이터를 서버에서 직접 HTML에 주입
- __INIT__ 글로벌 변수로 초기 데이터 전달 (fetch 불필요)
- 대시보드/사이트관리/AdSense/도메인/로그/사이트상세 전부 적용
- trust proxy 설정 (Traefik 뒤 동작)
- 저장/삭제/크롤링 등 액션은 여전히 API fetch 사용

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:24:57 +09:00

79 lines
4.5 KiB
Plaintext

<%- include('layout', { page: 'adsense', pageTitle: 'AdSense 관리', body: `
<div class="card">
<div class="card-header">
<h2>AdSense 설정 목록</h2>
<button class="btn btn-primary" onclick="openModal()">+ AdSense 추가</button>
</div>
<table>
<thead><tr><th>ID</th><th>이름</th><th>Client ID</th><th>상단 슬롯</th><th>중간 슬롯</th><th>하단 슬롯</th><th>상태</th><th>액션</th></tr></thead>
<tbody id="ads-tbody"></tbody>
</table>
</div>
<div class="modal-overlay" id="adsModal">
<div class="modal">
<h3 id="ads-modal-title">AdSense 추가</h3>
<input type="hidden" id="ads-edit-id">
<div class="form-group"><label>이름 (구분용)</label><input id="ads-name" placeholder="예: 메인사이트 애드센스"></div>
<div class="form-group"><label>Client ID (ca-pub-XXXX)</label><input id="ads-client" placeholder="ca-pub-1234567890123456"></div>
<div class="form-row">
<div class="form-group"><label>상단 광고 슬롯 ID (선택)</label><input id="ads-slot-top" placeholder="비워두면 자동광고"></div>
<div class="form-group"><label>중간 광고 슬롯 ID (선택)</label><input id="ads-slot-mid" placeholder="비워두면 자동광고"></div>
</div>
<div class="form-group"><label>하단 광고 슬롯 ID (선택)</label><input id="ads-slot-bot" placeholder="비워두면 자동광고"></div>
<div class="flex" style="justify-content:flex-end;gap:.5rem;margin-top:1rem">
<button class="btn btn-outline" onclick="closeModal()">취소</button>
<button class="btn btn-primary" onclick="saveAds()">저장</button>
</div>
</div>
</div>
<script>
var adsList = Array.isArray(__INIT__) ? __INIT__ : [];
function renderAds(){
document.getElementById('ads-tbody').innerHTML = adsList.map(function(a){
var slots=a.slots||{};
return '<tr><td>'+a.id+'</td><td><strong>'+a.name+'</strong></td><td class="text-muted">'+a.client_id+'</td>'+
'<td>'+(slots.top||'-')+'</td><td>'+(slots.middle||'-')+'</td><td>'+(slots.bottom||'-')+'</td>'+
'<td><span class="badge badge-'+(a.is_active?'success">활성':'danger">비활성')+'</span></td>'+
'<td class="flex"><button class="btn btn-outline btn-sm" onclick="editAds('+a.id+')">수정</button>'+
'<button class="btn btn-danger btn-sm" onclick="deleteAds('+a.id+')">삭제</button></td></tr>';
}).join('') || '<tr><td colspan="8" class="text-muted" style="text-align:center;padding:2rem">AdSense 설정을 추가하세요</td></tr>';
}
renderAds();
async function reloadAds(){var d=await api('GET','/api/adsense');if(d&&d.length!==undefined)adsList=d;renderAds();}
function openModal(){
document.getElementById('ads-modal-title').textContent='AdSense 추가';
document.getElementById('ads-edit-id').value='';
['ads-name','ads-client','ads-slot-top','ads-slot-mid','ads-slot-bot'].forEach(function(id){document.getElementById(id).value='';});
document.getElementById('adsModal').classList.add('active');
}
function editAds(id){
var a=adsList.find(function(x){return x.id===id});if(!a)return;
document.getElementById('ads-modal-title').textContent='AdSense 수정';
document.getElementById('ads-edit-id').value=a.id;
document.getElementById('ads-name').value=a.name;
document.getElementById('ads-client').value=a.client_id;
document.getElementById('ads-slot-top').value=(a.slots&&a.slots.top)||'';
document.getElementById('ads-slot-mid').value=(a.slots&&a.slots.middle)||'';
document.getElementById('ads-slot-bot').value=(a.slots&&a.slots.bottom)||'';
document.getElementById('adsModal').classList.add('active');
}
function closeModal(){document.getElementById('adsModal').classList.remove('active');}
async function saveAds(){
var data={name:document.getElementById('ads-name').value,client_id:document.getElementById('ads-client').value,
slots:{top:document.getElementById('ads-slot-top').value,middle:document.getElementById('ads-slot-mid').value,bottom:document.getElementById('ads-slot-bot').value},is_active:true};
if(!data.name||!data.client_id){toast('이름과 Client ID는 필수','error');return;}
var editId=document.getElementById('ads-edit-id').value;
if(editId){await api('PUT','/api/adsense/'+editId,data);toast('수정 완료');}
else{await api('POST','/api/adsense',data);toast('추가 완료');}
closeModal();await reloadAds();
}
async function deleteAds(id){if(!confirm('삭제하시겠습니까?'))return;await api('DELETE','/api/adsense/'+id);toast('삭제 완료');await reloadAds();}
</script>
` }) %>